home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 October / maximum-cd-2009-10.iso / DiscContents / Firefox Setup 3.5.exe / nonlocalized / chrome / toolkit.jar / content / mozapps / extensions / extensions.js < prev    next >
Encoding:
Text File  |  2009-06-24  |  103.9 KB  |  2,839 lines

  1. //@line 40 "e:\builds\moz2_slave\win32_build\build\toolkit\mozapps\extensions\content\extensions.js"
  2.  
  3. ///////////////////////////////////////////////////////////////////////////////
  4. // Globals
  5. const nsIExtensionManager    = Components.interfaces.nsIExtensionManager;
  6. const nsIUpdateItem          = Components.interfaces.nsIUpdateItem;
  7. const nsIFilePicker          = Components.interfaces.nsIFilePicker;
  8. const nsIIOService           = Components.interfaces.nsIIOService;
  9. const nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
  10. const nsIURL                 = Components.interfaces.nsIURL;
  11. const nsIAppStartup          = Components.interfaces.nsIAppStartup;
  12.  
  13. var gView             = null;
  14. var gExtensionManager = null;
  15. var gExtensionsView   = null;
  16. var gExtensionStrings = null;
  17. var gCurrentTheme     = "classic/1.0";
  18. var gDefaultTheme     = "classic/1.0";
  19. var gDownloadManager  = null;
  20. var gObserverIndex    = -1;
  21. var gInSafeMode       = false;
  22. var gCheckCompat      = true;
  23. var gCheckUpdateSecurity = true;
  24. var gUpdatesOnly      = false;
  25. var gAppID            = "";
  26. var gPref             = null;
  27. var gPriorityCount    = 0;
  28. var gInstalling       = false;
  29. var gPendingActions   = false;
  30. var gPlugins          = null;
  31. var gPluginsDS        = null;
  32. var gSearchDS         = null;
  33. var gAddonRepository  = null;
  34. var gShowGetAddonsPane = false;
  35. var gRetrievedResults = false;
  36. var gRecommendedAddons = null;
  37. var gRDF              = null;
  38. var gPendingInstalls  = {};
  39. var gNewAddons        = [];
  40.  
  41. const PREF_EM_CHECK_COMPATIBILITY           = "extensions.checkCompatibility";
  42. const PREF_EM_CHECK_UPDATE_SECURITY         = "extensions.checkUpdateSecurity";
  43. const PREF_EXTENSIONS_GETMORETHEMESURL      = "extensions.getMoreThemesURL";
  44. const PREF_EXTENSIONS_GETMOREEXTENSIONSURL  = "extensions.getMoreExtensionsURL";
  45. const PREF_EXTENSIONS_GETMOREPLUGINSURL     = "extensions.getMorePluginsURL";
  46. const PREF_EXTENSIONS_DSS_ENABLED           = "extensions.dss.enabled";
  47. const PREF_EXTENSIONS_DSS_SWITCHPENDING     = "extensions.dss.switchPending";
  48. const PREF_EXTENSIONS_HIDE_INSTALL_BTN      = "extensions.hideInstallButton";
  49. const PREF_DSS_SKIN_TO_SELECT               = "extensions.lastSelectedSkin";
  50. const PREF_GENERAL_SKINS_SELECTEDSKIN       = "general.skins.selectedSkin";
  51. const PREF_UPDATE_NOTIFYUSER                = "extensions.update.notifyUser";
  52. const PREF_GETADDONS_SHOWPANE               = "extensions.getAddons.showPane";
  53. const PREF_GETADDONS_REPOSITORY             = "extensions.getAddons.repository";
  54. const PREF_GETADDONS_MAXRESULTS             = "extensions.getAddons.maxResults";
  55.  
  56. const URI_GENERIC_ICON_XPINSTALL      = "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  57. const URI_GENERIC_ICON_THEME          = "chrome://mozapps/skin/extensions/themeGeneric.png";
  58.  
  59. //@line 101 "e:\builds\moz2_slave\win32_build\build\toolkit\mozapps\extensions\content\extensions.js"
  60. const URI_NOTIFICATION_ICON_INFO      = "chrome://global/skin/icons/information-16.png";
  61. const URI_NOTIFICATION_ICON_WARNING   = "chrome://global/skin/icons/warning-16.png";
  62. //@line 104 "e:\builds\moz2_slave\win32_build\build\toolkit\mozapps\extensions\content\extensions.js"
  63.  
  64. const RDFURI_ITEM_ROOT    = "urn:mozilla:item:root";
  65. const PREFIX_ITEM_URI     = "urn:mozilla:item:";
  66. const PREFIX_NS_EM        = "http://www.mozilla.org/2004/em-rdf#";
  67. const kXULNSURI           = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  68. const XMLURI_PARSE_ERROR  = "http://www.mozilla.org/newlayout/xml/parsererror.xml"
  69.  
  70. const OP_NONE                         = "";
  71. const OP_NEEDS_INSTALL                = "needs-install";
  72. const OP_NEEDS_UPGRADE                = "needs-upgrade";
  73. const OP_NEEDS_UNINSTALL              = "needs-uninstall";
  74. const OP_NEEDS_ENABLE                 = "needs-enable";
  75. const OP_NEEDS_DISABLE                = "needs-disable";
  76.  
  77. Components.utils.import("resource://gre/modules/PluralForm.jsm");
  78. Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
  79.  
  80. ///////////////////////////////////////////////////////////////////////////////
  81. // Utility Functions
  82. function setElementDisabledByID(aID, aDoDisable) {
  83.   var element = document.getElementById(aID);
  84.   if (element) {
  85.     if (aDoDisable)
  86.       element.setAttribute("disabled", "true");
  87.     else
  88.       element.removeAttribute("disabled");
  89.   }
  90. }
  91.  
  92. /**
  93.  * This returns the richlistitem element for the theme with the given
  94.  * internalName
  95.  */
  96. function getItemForInternalName(aInternalName) {
  97.   var property = gRDF.GetResource(PREFIX_NS_EM + "internalName");
  98.   var name = gRDF.GetLiteral(aInternalName);
  99.   var id = gExtensionManager.datasource.GetSource(property, name, true)
  100.   if (id && id instanceof Components.interfaces.nsIRDFResource)
  101.     return document.getElementById(id.ValueUTF8);
  102.   return null;
  103. }
  104.  
  105. function isSafeURI(aURI) {
  106.   try {
  107.     var uri = makeURI(aURI);
  108.     var scheme = uri.scheme;
  109.   } catch (ex) {}
  110.   return (uri && (scheme == "http" || scheme == "https" || scheme == "ftp"));
  111. }
  112.  
  113. function getBrandShortName() {
  114.   var brandStrings = document.getElementById("brandStrings");
  115.   return brandStrings.getString("brandShortName");
  116. }
  117.  
  118. function getExtensionString(key, strings) {
  119.   if (strings)
  120.     return gExtensionStrings.getFormattedString(key, strings);
  121.   return gExtensionStrings.getString(key);
  122. }
  123.  
  124. function MessageButton(aLabel, aAccesskey, aData) {
  125.   this.label = aLabel;
  126.   this.accessKey = aAccesskey;
  127.   this.data = aData || "addons-message-dismiss";
  128. }
  129. MessageButton.prototype = {
  130.   label: null,
  131.   accessKey: null,
  132.   data: null,
  133.  
  134.   callback: function (aNotification, aButton) {
  135.     var os = Components.classes["@mozilla.org/observer-service;1"]
  136.                        .getService(Components.interfaces.nsIObserverService);
  137.     os.notifyObservers(null, "addons-message-notification", aButton.data);
  138.     aNotification.close();
  139.     return true;
  140.   }
  141. };
  142.  
  143. function showMessage(aIconURL, aMessage, aButtonLabel, aButtonAccesskey,
  144.                      aShowCloseButton, aNotifyData) {
  145.   var addonsMsg = document.getElementById("addonsMsg");
  146.   var buttons = null;
  147.   if (aButtonLabel)
  148.     buttons = [new MessageButton(aButtonLabel, aButtonAccesskey, aNotifyData)];
  149.   var oldMessage = addonsMsg.getNotificationWithValue(aMessage);
  150.   if (oldMessage && oldMessage.parentNode)
  151.     addonsMsg.removeNotification(oldMessage);
  152.   if (addonsMsg.currentNotification)
  153.     gPriorityCount += 0.0001;
  154.   else
  155.     gPriorityCount = 0;
  156.   addonsMsg.appendNotification(aMessage, aMessage, aIconURL,
  157.                                addonsMsg.PRIORITY_WARNING_LOW + gPriorityCount,
  158.                                buttons).hideclose = !aShowCloseButton;
  159. }
  160.  
  161. // dynamically creates a template
  162. var AddonsViewBuilder = {
  163.   // if aActionList is null aBindingList will be used to generate actions
  164.   updateView: function(aRulesList, aURIList, aBindingList, aActionList)
  165.   {
  166.     var actionList = aActionList ? aActionList : aBindingList;
  167.  
  168.     this.clearChildren(gExtensionsView);
  169.     var template = document.createElementNS(kXULNSURI, "template");
  170.     gExtensionsView.appendChild(template);
  171.     for (var i = 0; i < aRulesList.length; ++i)
  172.       template.appendChild(this.createRule(aRulesList[i], aURIList[i], aBindingList[i], actionList[i]));
  173.  
  174.     gExtensionsView.builder.rebuild();
  175.   },
  176.  
  177.   clearChildren: function(aEl)
  178.   {
  179.     while (aEl.hasChildNodes())
  180.       aEl.removeChild(aEl.lastChild);
  181.   },
  182.  
  183.   createRule: function(aTriplesList, aURI, aBindingList, aActionList)
  184.   {
  185.     var rule = document.createElementNS(kXULNSURI, "rule");
  186.     var conditions = document.createElementNS(kXULNSURI, "conditions");
  187.     rule.appendChild(conditions);
  188.  
  189.     var content = document.createElementNS(kXULNSURI, "content");
  190.     content.setAttribute("uri", "?uri");
  191.     conditions.appendChild(content);
  192.  
  193.     var member = this.createMember("?uri", "?" + aURI);
  194.     conditions.appendChild(member);
  195.  
  196.     for (var i = 0; i < aTriplesList.length; ++i)
  197.       conditions.appendChild(this.createTriple("?" + aURI, PREFIX_NS_EM + aTriplesList[i][0], aTriplesList[i][1], aTriplesList[i][2]));
  198.  
  199.     var bindings = document.createElementNS(kXULNSURI, "bindings");
  200.     rule.appendChild(bindings);
  201.     for (i = 0; i < aBindingList.length; ++i)
  202.       bindings.appendChild(this.createBinding(aBindingList[i], aURI));
  203.  
  204.     var action = document.createElementNS(kXULNSURI, "action");
  205.     rule.appendChild(action);
  206.     var extension = document.createElementNS(kXULNSURI, aURI);
  207.     action.appendChild(extension);
  208.     extension.setAttribute("uri", "?" + aURI);
  209.     for (i = 0; i < aActionList.length; ++i)
  210.       extension.setAttribute(aActionList[i][0], aActionList[i][1]);
  211.  
  212.     return rule;
  213.   },
  214.  
  215.   createTriple: function(aSubject, aPredicate, aObject, aParseType)
  216.   {
  217.     var triple = document.createElementNS(kXULNSURI, "triple");
  218.     triple.setAttribute("subject", aSubject);
  219.     triple.setAttribute("predicate", aPredicate);
  220.     triple.setAttribute("object", aObject);
  221.     if (aParseType)
  222.       triple.setAttribute("parsetype", aParseType);
  223.     return triple;
  224.   },
  225.  
  226.   createBinding: function(aPredicateObjectList, aURI)
  227.   {
  228.     var binding = document.createElementNS(kXULNSURI, "binding");
  229.     binding.setAttribute("subject", "?" + aURI);
  230.     binding.setAttribute("predicate", PREFIX_NS_EM + aPredicateObjectList[0]);
  231.     binding.setAttribute("object", aPredicateObjectList[1]);
  232.     return binding;
  233.   },
  234.  
  235.   createMember: function(aContainer, aChild)
  236.   {
  237.     var member = document.createElementNS(kXULNSURI, "member");
  238.     member.setAttribute("container", aContainer);
  239.     member.setAttribute("child", aChild);
  240.  
  241.     return member;
  242.   }
  243. };
  244.  
  245. function showView(aView) {
  246.   if (gView == aView)
  247.     return;
  248.  
  249.   updateLastSelected(aView);
  250.   gView = aView;
  251.  
  252.   // Using disabled to represent add-on state in regards to the EM causes evil
  253.   // focus behavior when used as an element attribute when the element isn't
  254.   // really disabled.
  255.   var bindingList = [ [ ["aboutURL", "?aboutURL"],
  256.                         ["addonID", "?addonID"],
  257.                         ["availableUpdateURL", "?availableUpdateURL"],
  258.                         ["availableUpdateVersion", "?availableUpdateVersion"],
  259.                         ["blocklisted", "?blocklisted"],
  260.                         ["blocklistedsoft", "?blocklistedsoft"],
  261.                         ["compatible", "?compatible"],
  262.                         ["description", "?description"],
  263.                         ["downloadURL", "?downloadURL"],
  264.                         ["isDisabled", "?isDisabled"],
  265.                         ["hidden", "?hidden"],
  266.                         ["homepageURL", "?homepageURL"],
  267.                         ["iconURL", "?iconURL"],
  268.                         ["internalName", "?internalName"],
  269.                         ["locked", "?locked"],
  270.                         ["name", "?name"],
  271.                         ["optionsURL", "?optionsURL"],
  272.                         ["opType", "?opType"],
  273.                         ["plugin", "?plugin"],
  274.                         ["previewImage", "?previewImage"],
  275.                         ["satisfiesDependencies", "?satisfiesDependencies"],
  276.                         ["providesUpdatesSecurely", "?providesUpdatesSecurely"],
  277.                         ["type", "?type"],
  278.                         ["updateable", "?updateable"],
  279.                         ["updateURL", "?updateURL"],
  280.                         ["version", "?version"] ] ];
  281.   var displays = [ "richlistitem" ];
  282.  
  283.   var prefURL;
  284.   var showInstallFile = true;
  285.   try {
  286.     showInstallFile = !gPref.getBoolPref(PREF_EXTENSIONS_HIDE_INSTALL_BTN);
  287.   }
  288.   catch (e) { }
  289.   var showCheckUpdatesAll = true;
  290.   var showInstallUpdatesAll = false;
  291.   var showSkip = false;
  292.   switch (aView) {
  293.     case "search":
  294.       var bindingList = [ [ ["action", "?action"],
  295.                             ["addonID", "?addonID"],
  296.                             ["description", "?description"],
  297.                             ["eula", "?eula"],
  298.                             ["homepageURL", "?homepageURL"],
  299.                             ["iconURL", "?iconURL"],
  300.                             ["name", "?name"],
  301.                             ["previewImage", "?previewImage"],
  302.                             ["rating", "?rating"],
  303.                             ["addonType", "?addonType"],
  304.                             ["thumbnailURL", "?thumbnailURL"],
  305.                             ["version", "?version"],
  306.                             ["xpiHash", "?xpiHash"],
  307.                             ["xpiURL", "?xpiURL"],
  308.                             ["typeName", "searchResult"] ],
  309.                           [ ["type", "?type"],
  310.                             ["typeName", "status"],
  311.                             ["count", "?count"],
  312.                             ["link", "?link" ] ] ];
  313.       var types = [ [ ["searchResult", "true", null] ],
  314.                     [ ["statusMessage", "true", null] ] ];
  315.       var displays = [ "richlistitem", "vbox" ];
  316.       showCheckUpdatesAll = false;
  317.       document.getElementById("searchfield").disabled = isOffline("offlineSearchMsg");
  318.       break;
  319.     case "extensions":
  320.       prefURL = PREF_EXTENSIONS_GETMOREEXTENSIONSURL;
  321.       types = [ [ ["type", nsIUpdateItem.TYPE_EXTENSION, "Integer"] ] ];
  322.       break;
  323.     case "themes":
  324.       prefURL = PREF_EXTENSIONS_GETMORETHEMESURL;
  325.       types = [ [ ["type", nsIUpdateItem.TYPE_THEME, "Integer"] ] ];
  326.       break;
  327.     case "locales":
  328.       types = [ [ ["type", nsIUpdateItem.TYPE_LOCALE, "Integer"] ] ];
  329.       break;
  330.     case "plugins":
  331.       prefURL = PREF_EXTENSIONS_GETMOREPLUGINSURL;
  332.       types = [ [ ["plugin", "true", null] ] ];
  333.       showCheckUpdatesAll = false;
  334.       break;
  335.     case "updates":
  336.       document.getElementById("updates-view").hidden = false;
  337.       showInstallFile = false;
  338.       showCheckUpdatesAll = false;
  339.       showInstallUpdatesAll = true;
  340.       if (gUpdatesOnly)
  341.         showSkip = true;
  342.       bindingList = [ [ ["aboutURL", "?aboutURL"],
  343.                         ["availableUpdateURL", "?availableUpdateURL"],
  344.                         ["availableUpdateVersion", "?availableUpdateVersion"],
  345.                         ["availableUpdateInfo", "?availableUpdateInfo"],
  346.                         ["blocklisted", "?blocklisted"],
  347.                         ["blocklistedsoft", "?blocklistedsoft"],
  348.                         ["homepageURL", "?homepageURL"],
  349.                         ["iconURL", "?iconURL"],
  350.                         ["internalName", "?internalName"],
  351.                         ["locked", "?locked"],
  352.                         ["name", "?name"],
  353.                         ["opType", "?opType"],
  354.                         ["previewImage", "?previewImage"],
  355.                         ["satisfiesDependencies", "?satisfiesDependencies"],
  356.                         ["providesUpdatesSecurely", "?providesUpdatesSecurely"],
  357.                         ["type", "?type"],
  358.                         ["updateURL", "?updateURL"],
  359.                         ["version", "?version"],
  360.                         ["typeName", "update"] ] ];
  361.       types = [ [ ["availableUpdateVersion", "?availableUpdateVersion", null],
  362.                   ["updateable", "true", null] ] ];
  363.       break;
  364.     case "installs":
  365.       document.getElementById("installs-view").hidden = false;
  366.       showInstallFile = false;
  367.       showCheckUpdatesAll = false;
  368.       showInstallUpdatesAll = false;
  369.       bindingList = [ [ ["aboutURL", "?aboutURL"],
  370.                         ["addonID", "?addonID"],
  371.                         ["availableUpdateURL", "?availableUpdateURL"],
  372.                         ["availableUpdateVersion", "?availableUpdateVersion"],
  373.                         ["blocklisted", "?blocklisted"],
  374.                         ["blocklistedsoft", "?blocklistedsoft"],
  375.                         ["compatible", "?compatible"],
  376.                         ["description", "?description"],
  377.                         ["downloadURL", "?downloadURL"],
  378.                         ["incompatibleUpdate", "?incompatibleUpdate"],
  379.                         ["isDisabled", "?isDisabled"],
  380.                         ["hidden", "?hidden"],
  381.                         ["homepageURL", "?homepageURL"],
  382.                         ["iconURL", "?iconURL"],
  383.                         ["internalName", "?internalName"],
  384.                         ["locked", "?locked"],
  385.                         ["name", "?name"],
  386.                         ["optionsURL", "?optionsURL"],
  387.                         ["opType", "?opType"],
  388.                         ["previewImage", "?previewImage"],
  389.                         ["progress", "?progress"],
  390.                         ["state", "?state"],
  391.                         ["type", "?type"],
  392.                         ["updateable", "?updateable"],
  393.                         ["updateURL", "?updateURL"],
  394.                         ["version", "?version"],
  395.                         ["newVersion", "?newVersion"],
  396.                         ["typeName", "install"] ] ];
  397.       types = [ [ ["state", "?state", null] ] ];
  398.       break;
  399.   }
  400.  
  401.   var showGetMore = false;
  402.   var getMore = document.getElementById("getMore");
  403.   if (prefURL && !gShowGetAddonsPane) {
  404.     try {
  405.       getMore.setAttribute("value", getMore.getAttribute("value" + aView));
  406.       var getMoreURL = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
  407.                                  .getService(Components.interfaces.nsIURLFormatter)
  408.                                  .formatURLPref(prefURL);
  409.       getMore.setAttribute("getMoreURL", getMoreURL);
  410.       showGetMore = getMoreURL == "about:blank" ? false : true;
  411.     }
  412.     catch (e) { }
  413.   }
  414.   getMore.hidden = !showGetMore;
  415.  
  416.   var isThemes = aView == "themes";
  417.  
  418.   if (aView == "themes" || aView == "extensions") {
  419.     var el = document.getElementById("installFileButton");
  420.     el.setAttribute("tooltiptext", el.getAttribute(isThemes ? "tooltiptextthemes" :
  421.                                                               "tooltiptextaddons"));
  422.     el = document.getElementById("checkUpdatesAllButton");
  423.     el.setAttribute("tooltiptext", el.getAttribute(isThemes ? "tooltiptextthemes" :
  424.                                                               "tooltiptextaddons"));
  425.   }
  426.  
  427.   document.getElementById("installFileButton").hidden = !showInstallFile;
  428.   document.getElementById("checkUpdatesAllButton").hidden = !showCheckUpdatesAll;
  429.   document.getElementById("installUpdatesAllButton").hidden = !showInstallUpdatesAll;
  430.   document.getElementById("skipDialogButton").hidden = !showSkip;
  431.   document.getElementById("themePreviewArea").hidden = !isThemes;
  432.   document.getElementById("themeSplitter").hidden = !isThemes;
  433.   document.getElementById("showUpdateInfoButton").hidden = aView != "updates";
  434.   document.getElementById("hideUpdateInfoButton").hidden = true;
  435.   document.getElementById("searchPanel").hidden = aView != "search";
  436.  
  437.   AddonsViewBuilder.updateView(types, displays, bindingList, null);
  438.  
  439.   if (aView == "updates" || aView == "installs")
  440.     gExtensionsView.selectedItem = gExtensionsView.children[0];
  441.  
  442.   if (showSkip) {
  443.     var button = document.getElementById("installUpdatesAllButton");
  444.     button.setAttribute("default", "true");
  445.     window.setTimeout(function () { button.focus(); }, 0);
  446.   } else
  447.     document.getElementById("installUpdatesAllButton").removeAttribute("default");
  448.  
  449.   if (isThemes)
  450.     onAddonSelect();
  451.   updateGlobalCommands();
  452. }
  453.  
  454. // manages the last-selected attribute for the view buttons and richlistbox
  455. function updateLastSelected(aView) {
  456.   var viewGroup = document.getElementById("viewGroup");
  457.   if (viewGroup.hasAttribute("last-selected"))
  458.     var lastSelectedView = viewGroup.getAttribute("last-selected");
  459.  
  460.   if (lastSelectedView && lastSelectedView == gView) {
  461.     var lastViewButton = document.getElementById(lastSelectedView + "-view");
  462.     if (lastViewButton.hasAttribute("persist")) {
  463.       if (gExtensionsView.selectedItem)
  464.         lastViewButton.setAttribute("last-selected", gExtensionsView.selectedItem.id);
  465.       else if (lastViewButton.hasAttribute("last-selected"))
  466.         lastViewButton.removeAttribute("last-selected");
  467.     }
  468.   }
  469.   var viewButton = document.getElementById(aView + "-view");
  470.   if (viewButton.hasAttribute("last-selected")) {
  471.     gExtensionsView.setAttribute("last-selected", viewButton.getAttribute("last-selected"));
  472.   }
  473.   else if (gExtensionsView.hasAttribute("last-selected")) {
  474.     gExtensionsView.clearSelection();
  475.     gExtensionsView.removeAttribute("last-selected");
  476.   }
  477.   viewGroup.selectedItem = viewButton;
  478.   // Only set last-selected for view buttons that have a persist attribute
  479.   // (e.g. they themselves persist the last selected add-on in the view).
  480.   // This prevents opening updates and installs views when they were the last
  481.   // view selected and instead this will open the previously selected
  482.   // extensions, themes, locales, plug-ins, etc. view.
  483.   if (viewButton.hasAttribute("persist"))
  484.     viewGroup.setAttribute("last-selected", aView);
  485. }
  486.  
  487. function LOG(msg) {
  488.   dump("*** " + msg + "\n");
  489. }
  490.  
  491. function getIDFromResourceURI(aURI)
  492. {
  493.   if (aURI.substring(0, PREFIX_ITEM_URI.length) == PREFIX_ITEM_URI)
  494.     return aURI.substring(PREFIX_ITEM_URI.length);
  495.   return aURI;
  496. }
  497.  
  498. function showProgressBar() {
  499.   var progressBox = document.getElementById("progressBox");
  500.   var height = document.defaultView.getComputedStyle(progressBox.parentNode, "")
  501.                        .getPropertyValue("height");
  502.   progressBox.parentNode.style.height = height;
  503.   document.getElementById("viewGroup").hidden = true;
  504.   progressBox.hidden = false;
  505. }
  506.  
  507. function flushDataSource()
  508. {
  509.   var rds = gExtensionManager.datasource.QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
  510.   if (rds)
  511.     rds.Flush();
  512. }
  513.  
  514. function noUpdatesDismiss(aEvent)
  515. {
  516.   window.removeEventListener("select", noUpdatesDismiss, true);
  517.  
  518.   var children = gExtensionsView.children;
  519.   for (var i = 0; i < children.length; ++i) {
  520.     var child = children[i];
  521.     if (child.hasAttribute("updateStatus"))
  522.       child.removeAttribute("updateStatus");
  523.   }
  524.  
  525.   if (aEvent.target.localName != "notification")
  526.     document.getElementById("addonsMsg").removeCurrentNotification();
  527. }
  528.  
  529. function clearRestartMessage()
  530. {
  531.   var children = gExtensionsView.children;
  532.   for (var i = 0; i < children.length; ++i) {
  533.     var item = children[i];
  534.     if (item.hasAttribute("oldDescription")) {
  535.       item.setAttribute("description", item.getAttribute("oldDescription"));
  536.       item.removeAttribute("oldDescription");
  537.     }
  538.   }
  539. }
  540.  
  541. function setRestartMessage(aItem)
  542. {
  543.   var themeName = aItem.getAttribute("name");
  544.   var restartMessage = getExtensionString("dssSwitchAfterRestart",
  545.                                           [getBrandShortName()]);
  546.   aItem.setAttribute("oldDescription", aItem.getAttribute("description"));
  547.   aItem.setAttribute("description", restartMessage);
  548. }
  549.  
  550. // Removes any assertions in the datasource about a given resource
  551. function cleanResource(ds, resource) {
  552.   // Remove outward arcs
  553.   var arcs = ds.ArcLabelsOut(resource);
  554.   while (arcs.hasMoreElements()) {
  555.     var arc = arcs.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  556.     var targets = ds.GetTargets(resource, arc, true);
  557.     while (targets.hasMoreElements()) {
  558.       var value = targets.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  559.       if (value)
  560.         ds.Unassert(resource, arc, value);
  561.     }
  562.   }
  563. }
  564.  
  565. // Wipes the datasource clean of assertions
  566. function cleanDataSource(ds, rootctr) {
  567.   // Remove old entries from the list
  568.   var nodes = rootctr.GetElements();
  569.   while (nodes.hasMoreElements()) {
  570.     var node = nodes.getNext()
  571.                     .QueryInterface(Components.interfaces.nsIRDFResource);
  572.     rootctr.RemoveElement(node, false);
  573.     cleanResource(ds, node);
  574.   }
  575. }
  576.  
  577. // Displays the search status message
  578. function displaySearchThrobber(aKey) {
  579.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  580.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  581.   var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  582.  
  583.   cleanDataSource(gSearchDS, rootctr);
  584.  
  585.   var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
  586.   rootctr.AppendElement(labelNode);
  587.   gSearchDS.Assert(labelNode,
  588.                    gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  589.                    gRDF.GetLiteral("true"),
  590.                    true);
  591.   gSearchDS.Assert(labelNode,
  592.                    gRDF.GetResource(PREFIX_NS_EM + "type"),
  593.                    gRDF.GetLiteral(aKey),
  594.                    true);
  595. }
  596.  
  597. // Clears the search box and updates the result list
  598. function resetSearch() {
  599.   var searchfield = document.getElementById("searchfield");
  600.   searchfield.value = "";
  601.   searchfield.focus();
  602.   retrieveRepositoryAddons("");
  603. }
  604.  
  605. // Searches for results
  606. function retrieveRepositoryAddons(aTerms) {
  607.   if (gAddonRepository.isSearching)
  608.     gAddonRepository.cancelSearch();
  609.   if (aTerms) {
  610.     displaySearchThrobber("retrieve-search");
  611.     gAddonRepository.searchAddons(aTerms,
  612.                                   gPref.getIntPref(PREF_GETADDONS_MAXRESULTS),
  613.                                   AddonSearchResults);
  614.   }
  615.   else {
  616.     if (gRecommendedAddons) {
  617.       displaySearchResults(gRecommendedAddons, -1, true);
  618.     }
  619.     else {
  620.       displaySearchThrobber("retrieve-recommended");
  621.       gAddonRepository.retrieveRecommendedAddons(gPref.getIntPref(PREF_GETADDONS_MAXRESULTS),
  622.                                                  RecommendedSearchResults);
  623.     }
  624.   }
  625.   gRetrievedResults = true;
  626. }
  627.  
  628. // Puts search results into the search datasource
  629. function displaySearchResults(addons, count, isRecommended) {
  630.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  631.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  632.   var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  633.  
  634.   gSearchDS.beginUpdateBatch();
  635.  
  636.   cleanDataSource(gSearchDS, rootctr);
  637.  
  638.   if (isRecommended) {
  639.     var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
  640.     rootctr.AppendElement(labelNode);
  641.     gSearchDS.Assert(labelNode,
  642.                      gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  643.                      gRDF.GetLiteral("true"),
  644.                      true);
  645.     gSearchDS.Assert(labelNode,
  646.                      gRDF.GetResource(PREFIX_NS_EM + "type"),
  647.                      gRDF.GetLiteral("header-recommended"),
  648.                      true);
  649.  
  650.     // Locale sensitive sort
  651.     function compare(a, b) {
  652.       return String.localeCompare(a.name, b.name);
  653.     }
  654.     addons.sort(compare);
  655.   }
  656.   
  657.   if (addons.length == 0 && (isRecommended || count > 0)) {
  658.     var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:noresults");
  659.     rootctr.AppendElement(labelNode);
  660.     gSearchDS.Assert(labelNode,
  661.                      gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  662.                      gRDF.GetLiteral("true"),
  663.                      true);
  664.     if (isRecommended) {
  665.       gSearchDS.Assert(labelNode,
  666.                        gRDF.GetResource(PREFIX_NS_EM + "type"),
  667.                        gRDF.GetLiteral("message-norecommended"),
  668.                        true);
  669.     }
  670.     else {
  671.       gSearchDS.Assert(labelNode,
  672.                        gRDF.GetResource(PREFIX_NS_EM + "type"),
  673.                        gRDF.GetLiteral("message-nosearchresults"),
  674.                        true);
  675.     }
  676.   }
  677.  
  678.   var urlproperties = [ "iconURL", "homepageURL", "thumbnailURL", "xpiURL" ];
  679.   var properties = [ "name", "eula", "iconURL", "homepageURL", "thumbnailURL", "xpiURL", "xpiHash" ];
  680.   for (var i = 0; i < addons.length; i++) {
  681.     var addon = addons[i];
  682.     // Strip out any items with potentially unsafe urls
  683.     var unsafe = false;
  684.     for (var j = 0; j < urlproperties.length; j++) {
  685.       if (!isSafeURI(addon[urlproperties[j]])) {
  686.         unsafe = true;
  687.         break;
  688.       }
  689.     }
  690.     if (unsafe)
  691.       continue;
  692.  
  693.     var resultNode = gRDF.GetResource("urn:mozilla:addons:search:" + addon.xpiURL);
  694.     gSearchDS.Assert(resultNode,
  695.                      gRDF.GetResource(PREFIX_NS_EM + "addonID"),
  696.                      gRDF.GetLiteral(addon.id),
  697.                      true);
  698.     // Use the short summary for our "description"
  699.     gSearchDS.Assert(resultNode,
  700.                      gRDF.GetResource(PREFIX_NS_EM + "description"),
  701.                      gRDF.GetLiteral(addon.summary),
  702.                      true);
  703.     gSearchDS.Assert(resultNode,
  704.                      gRDF.GetResource(PREFIX_NS_EM + "addonType"),
  705.                      gRDF.GetIntLiteral(addon.type),
  706.                      true);
  707.     if (addon.rating >= 0) {
  708.       gSearchDS.Assert(resultNode,
  709.                        gRDF.GetResource(PREFIX_NS_EM + "rating"),
  710.                        gRDF.GetIntLiteral(addon.rating),
  711.                        gRDF.GetIntLiteral(3),
  712.                        true);
  713.     }
  714.  
  715.     for (var j = 0; j < properties.length; j++) {
  716.       gSearchDS.Assert(resultNode,
  717.                        gRDF.GetResource(PREFIX_NS_EM + properties[j]),
  718.                        gRDF.GetLiteral(addon[properties[j]]),
  719.                        true);
  720.     }
  721.     gSearchDS.Assert(resultNode,
  722.                      gRDF.GetResource(PREFIX_NS_EM + "searchResult"),
  723.                      gRDF.GetLiteral("true"),
  724.                      true);
  725.     rootctr.AppendElement(resultNode);
  726.   }
  727.  
  728.   labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:footer");
  729.   rootctr.AppendElement(labelNode);
  730.   gSearchDS.Assert(labelNode,
  731.                    gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  732.                    gRDF.GetLiteral("true"),
  733.                    true);
  734.   if (isRecommended) {
  735.     gSearchDS.Assert(labelNode,
  736.                      gRDF.GetResource(PREFIX_NS_EM + "type"),
  737.                      gRDF.GetLiteral("footer-recommended"),
  738.                      true);
  739.     var url = gAddonRepository.getRecommendedURL();
  740.   }
  741.   else {
  742.     gSearchDS.Assert(labelNode,
  743.                      gRDF.GetResource(PREFIX_NS_EM + "type"),
  744.                      gRDF.GetLiteral("footer-search"),
  745.                      true);
  746.     gSearchDS.Assert(labelNode,
  747.                      gRDF.GetResource(PREFIX_NS_EM + "count"),
  748.                      gRDF.GetIntLiteral(count),
  749.                      true);
  750.     var searchfield = document.getElementById("searchfield");
  751.     url = gAddonRepository.getSearchURL(searchfield.value);
  752.   }
  753.   gSearchDS.Assert(labelNode,
  754.                    gRDF.GetResource(PREFIX_NS_EM + "link"),
  755.                    gRDF.GetLiteral(url),
  756.                    true);
  757.  
  758.   gSearchDS.endUpdateBatch();
  759. }
  760.  
  761. // Displays the search failure status message
  762. function displaySearchFailure(isRecommended) {
  763.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  764.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  765.   var rootctr = rdfCU.MakeSeq(gSearchDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  766.  
  767.   cleanDataSource(gSearchDS, rootctr);
  768.  
  769.   var labelNode = gRDF.GetResource("urn:mozilla:addons:search:status:header");
  770.   rootctr.AppendElement(labelNode);
  771.   gSearchDS.Assert(labelNode,
  772.                    gRDF.GetResource(PREFIX_NS_EM + "statusMessage"),
  773.                    gRDF.GetLiteral("true"),
  774.                    true);
  775.   gSearchDS.Assert(labelNode,
  776.                    gRDF.GetResource(PREFIX_NS_EM + "type"),
  777.                    gRDF.GetLiteral(isRecommended ? "recommended-failure" : "search-failure"),
  778.                    true);
  779. }
  780.  
  781. // nsIAddonSearchResultsCallback for the recommended search
  782. var RecommendedSearchResults = {
  783.   searchSucceeded: function(aAddons, aAddonCount, aTotalResults) {
  784.     gRecommendedAddons = aAddons;
  785.     displaySearchResults(aAddons, aTotalResults, true);
  786.   },
  787.  
  788.   searchFailed: function() {
  789.     displaySearchFailure(true);
  790.   }
  791. }
  792.  
  793. // nsIAddonSearchResultsCallback for a standard search
  794. var AddonSearchResults = {
  795.   searchSucceeded: function(aAddons, aAddonCount, aTotalResults) {
  796.     displaySearchResults(aAddons, aTotalResults, false);
  797.   },
  798.  
  799.   searchFailed: function() {
  800.     displaySearchFailure(false);
  801.   }
  802. }
  803.  
  804. // Initialises the search repository and the results datasource
  805. function initSearchDS() {
  806.   var repository = "@mozilla.org/extensions/addon-repository;1";
  807.   try {
  808.     var repo = gPref.getCharPref(PREF_GETADDONS_REPOSITORY);
  809.     if (repo in Components.classes)
  810.       repository = repo;
  811.   } catch (e) { }
  812.   gAddonRepository = Components.classes[repository]
  813.                                .createInstance(Components.interfaces.nsIAddonRepository);
  814.   var browseAddons = document.getElementById("browseAddons");
  815.   var homepage = gAddonRepository.homepageURL;
  816.   if (homepage)
  817.     browseAddons.setAttribute("homepageURL", homepage);
  818.   else
  819.     browseAddons.hidden = true;
  820.   gSearchDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
  821.                         .createInstance(Components.interfaces.nsIRDFDataSource);
  822.   gExtensionsView.database.AddDataSource(gSearchDS);
  823.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  824.                             .getService(nsIIOService);
  825.   if (!ioService.offline)
  826.     retrieveRepositoryAddons(document.getElementById("searchfield").value);
  827. }
  828.  
  829. function initPluginsDS()
  830. {
  831.   gPluginsDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
  832.                          .createInstance(Components.interfaces.nsIRDFDataSource);
  833.   rebuildPluginsDS();
  834. }
  835.  
  836. function rebuildPluginsDS()
  837. {
  838.   var phs = Components.classes["@mozilla.org/plugin/host;1"]
  839.                       .getService(Components.interfaces.nsIPluginHost);
  840.   var plugins = phs.getPluginTags({ });
  841.   var rdfCU = Components.classes["@mozilla.org/rdf/container-utils;1"]
  842.                         .getService(Components.interfaces.nsIRDFContainerUtils);
  843.   var rootctr = rdfCU.MakeSeq(gPluginsDS, gRDF.GetResource(RDFURI_ITEM_ROOT));
  844.   gPlugins = { };
  845.   
  846.   // Running in a batch stops the template builder from running
  847.   gPluginsDS.beginUpdateBatch();
  848.  
  849.   cleanDataSource(gPluginsDS, rootctr);
  850.  
  851.   // Locale sensitive sort
  852.   function compare(a, b) {
  853.     return String.localeCompare(a.name, b.name);
  854.   }
  855.   plugins.sort(compare);
  856.  
  857.   for (var i = 0; i < plugins.length; i++) {
  858.     var plugin = plugins[i];
  859.     var name = plugin.name;
  860.     if (!(name in gPlugins))
  861.       gPlugins[name] = { };
  862.  
  863.     // Removes all html markup in a plugin's description
  864.     var desc = plugin.description.replace(/<\/?[a-z][^>]*>/gi, " ");
  865.     if (!(desc in gPlugins[name])) {
  866.       var homepageURL = null;
  867.       // Some plugins (e.g. QuickTime) add an anchor to their description to
  868.       // provide a link to the plugin's homepage in about:plugins. This can be
  869.       // used to provide access to a plugins homepage in the add-ons mgr.
  870.       if (/<A\s+HREF=[^>]*>/i.test(plugin.description))
  871.         homepageURL = /<A\s+HREF=["']?([^>"'\s]*)/i.exec(plugin.description)[1];
  872.  
  873.       gPlugins[name][desc] = { filename    : plugin.filename,
  874.                                version     : plugin.version,
  875.                                homepageURL : homepageURL,
  876.                                disabled    : plugin.disabled,
  877.                                blocklisted : plugin.blocklisted,
  878.                                plugins     : [] };
  879.     }
  880.     gPlugins[name][desc].plugins.push(plugin);
  881.   }
  882.  
  883.   var blocklist = Components.classes["@mozilla.org/extensions/blocklist;1"]
  884.                             .getService(Components.interfaces.nsIBlocklistService);
  885.   for (var pluginName in gPlugins) {
  886.     for (var pluginDesc in gPlugins[pluginName]) {
  887.       plugin = gPlugins[pluginName][pluginDesc];
  888.       var pluginNode = gRDF.GetResource(PREFIX_ITEM_URI + plugin.filename);
  889.       rootctr.AppendElement(pluginNode);
  890.       gPluginsDS.Assert(pluginNode,
  891.                         gRDF.GetResource(PREFIX_NS_EM + "name"),
  892.                         gRDF.GetLiteral(pluginName),
  893.                         true);
  894.       gPluginsDS.Assert(pluginNode,
  895.                         gRDF.GetResource(PREFIX_NS_EM + "version"),
  896.                         gRDF.GetLiteral(plugin.version),
  897.                         true);
  898.       gPluginsDS.Assert(pluginNode,
  899.                         gRDF.GetResource(PREFIX_NS_EM + "addonID"),
  900.                         gRDF.GetLiteral(plugin.filename),
  901.                         true);
  902.       gPluginsDS.Assert(pluginNode,
  903.                         gRDF.GetResource(PREFIX_NS_EM + "description"),
  904.                         gRDF.GetLiteral(pluginDesc),
  905.                         true);
  906.       if (plugin.homepageURL)
  907.         gPluginsDS.Assert(pluginNode,
  908.                           gRDF.GetResource(PREFIX_NS_EM + "homepageURL"),
  909.                           gRDF.GetLiteral(plugin.homepageURL),
  910.                           true);
  911.       gPluginsDS.Assert(pluginNode,
  912.                         gRDF.GetResource(PREFIX_NS_EM + "isDisabled"),
  913.                         gRDF.GetLiteral((plugin.disabled ||
  914.                                          plugin.blocklisted) ? "true" : "false"),
  915.                         true);
  916.       gPluginsDS.Assert(pluginNode,
  917.                         gRDF.GetResource(PREFIX_NS_EM + "blocklisted"),
  918.                         gRDF.GetLiteral(plugin.blocklisted ? "true" : "false"),
  919.                         true);
  920.       var softblocked = blocklist.getPluginBlocklistState(plugin) == 
  921.                         Components.interfaces.nsIBlocklistService.STATE_SOFTBLOCKED;
  922.       gPluginsDS.Assert(pluginNode,
  923.                         gRDF.GetResource(PREFIX_NS_EM + "blocklistedsoft"),
  924.                         gRDF.GetLiteral(softblocked ? "true" : "false"),
  925.                         true);
  926.       gPluginsDS.Assert(pluginNode,
  927.                         gRDF.GetResource(PREFIX_NS_EM + "compatible"),
  928.                         gRDF.GetLiteral("true"),
  929.                         true);
  930.       gPluginsDS.Assert(pluginNode,
  931.                         gRDF.GetResource(PREFIX_NS_EM + "plugin"),
  932.                         gRDF.GetLiteral("true"),
  933.                         true);
  934.     }
  935.   }
  936.   
  937.   gPluginsDS.endUpdateBatch();
  938. }
  939.  
  940. function togglePluginDisabled(aName, aDesc)
  941. {
  942.   var plugin = gPlugins[aName][aDesc];
  943.   plugin.disabled = !plugin.disabled;
  944.   for (var i = 0; i < plugin.plugins.length; ++i)
  945.     plugin.plugins[i].disabled = plugin.disabled;
  946.   var isDisabled = plugin.disabled || plugin.blocklisted;
  947.   gPluginsDS.Change(gRDF.GetResource(PREFIX_ITEM_URI + plugin.filename),
  948.                     gRDF.GetResource(PREFIX_NS_EM + "isDisabled"),
  949.                     gRDF.GetLiteral(isDisabled ? "false" : "true"),
  950.                     gRDF.GetLiteral(isDisabled ? "true" : "false"));
  951.   gExtensionsViewController.onCommandUpdate();
  952.   gExtensionsView.selectedItem.focus();
  953. }
  954.  
  955. ///////////////////////////////////////////////////////////////////////////////
  956. // Startup, Shutdown
  957. function Startup()
  958. {
  959.   gExtensionStrings = document.getElementById("extensionsStrings");
  960.   gPref = Components.classes["@mozilla.org/preferences-service;1"]
  961.                     .getService(Components.interfaces.nsIPrefBranch2);
  962.   var defaultPref = gPref.QueryInterface(Components.interfaces.nsIPrefService)
  963.                          .getDefaultBranch(null);
  964.   try {
  965.     gCurrentTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  966.     gDefaultTheme = defaultPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  967.     if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING))
  968.       gCurrentTheme = gPref.getCharPref(PREF_DSS_SKIN_TO_SELECT);
  969.   }
  970.   catch (e) { }
  971.  
  972.   gExtensionsView = document.getElementById("extensionsView");
  973.   gExtensionManager = Components.classes["@mozilla.org/extensions/manager;1"]
  974.                                 .getService(nsIExtensionManager);
  975.   var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
  976.                           .getService(Components.interfaces.nsIXULAppInfo)
  977.                           .QueryInterface(Components.interfaces.nsIXULRuntime);
  978.   gInSafeMode = appInfo.inSafeMode;
  979.   gAppID = appInfo.ID;
  980.  
  981.   try {
  982.     gCheckCompat = gPref.getBoolPref(PREF_EM_CHECK_COMPATIBILITY);
  983.   } catch(e) { }
  984.  
  985.   try {
  986.     gCheckUpdateSecurity = gPref.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY);
  987.   } catch(e) { }
  988.  
  989.   gPref.addObserver(PREF_DSS_SKIN_TO_SELECT, gPrefObserver, false);
  990.   gPref.addObserver(PREF_GENERAL_SKINS_SELECTEDSKIN, gPrefObserver, false);
  991.  
  992.   try {
  993.     gShowGetAddonsPane = gPref.getBoolPref(PREF_GETADDONS_SHOWPANE);
  994.   } catch(e) { }
  995.  
  996.   // Sort on startup and anytime an add-on is installed or upgraded.
  997.   gExtensionManager.sortTypeByProperty(nsIUpdateItem.TYPE_ANY, "name", true);
  998.   // Extension Command Updating is handled by a command controller.
  999.   gExtensionsView.controllers.appendController(gExtensionsViewController);
  1000.   gExtensionsView.addEventListener("select", onAddonSelect, false);
  1001.  
  1002.   gRDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
  1003.                    .getService(Components.interfaces.nsIRDFService);
  1004.  
  1005.   initPluginsDS();
  1006.   gExtensionsView.database.AddDataSource(gPluginsDS);
  1007.   if (gShowGetAddonsPane)
  1008.     initSearchDS();
  1009.   gExtensionsView.database.AddDataSource(gExtensionManager.datasource);
  1010.   gExtensionsView.setAttribute("ref", RDFURI_ITEM_ROOT);
  1011.  
  1012.   document.getElementById("search-view").hidden = !gShowGetAddonsPane;
  1013.   updateOptionalViews();
  1014.  
  1015.   var viewGroup = document.getElementById("viewGroup");
  1016.  
  1017.   gExtensionsView.focus();
  1018.   gExtensionsViewController.onCommandUpdate();
  1019.  
  1020.   // Now look and see if we're being opened by XPInstall
  1021.   gDownloadManager = new XPInstallDownloadManager();
  1022.   var os = Components.classes["@mozilla.org/observer-service;1"]
  1023.                      .getService(Components.interfaces.nsIObserverService);
  1024.   os.addObserver(gDownloadManager, "xpinstall-download-started", false);
  1025.   os.addObserver(gAddonsMsgObserver, "addons-message-notification", false);
  1026.   os.addObserver(gPluginObserver, "plugins-list-updated", false);
  1027.  
  1028.   gObserverIndex = gExtensionManager.addInstallListener(gDownloadManager);
  1029.  
  1030.   if (!gCheckCompat) {
  1031.     var msgText = getExtensionString("disabledCompatMsg");
  1032.     var buttonLabel = getExtensionString("enableButtonLabel");
  1033.     var buttonAccesskey = getExtensionString("enableButtonAccesskey");
  1034.     var notifyData = "addons-enable-compatibility";
  1035.     showMessage(URI_NOTIFICATION_ICON_WARNING,
  1036.                 msgText, buttonLabel, buttonAccesskey,
  1037.                 true, notifyData);
  1038.   }
  1039.   if (!gCheckUpdateSecurity) {
  1040.     var defaultCheckSecurity = true;
  1041.     try {
  1042.       defaultCheckSecurity = defaultPref.getBoolPref(PREF_EM_CHECK_UPDATE_SECURITY);
  1043.     } catch (e) { }
  1044.  
  1045.     // App has update security checking enabled by default so show warning
  1046.     if (defaultCheckSecurity) {
  1047.       var msgText = getExtensionString("disabledUpdateSecurityMsg");
  1048.       var buttonLabel = getExtensionString("enableButtonLabel");
  1049.       var buttonAccesskey = getExtensionString("enableButtonAccesskey");
  1050.       var notifyData = "addons-enable-updatesecurity";
  1051.       showMessage(URI_NOTIFICATION_ICON_WARNING,
  1052.                   msgText, buttonLabel, buttonAccesskey,
  1053.                   true, notifyData);
  1054.     }
  1055.   }
  1056.   if (gInSafeMode) {
  1057.     showMessage(URI_NOTIFICATION_ICON_INFO,
  1058.                 getExtensionString("safeModeMsg"),
  1059.                 null, null, true, null);
  1060.   }
  1061.  
  1062.   gExtensionsView.builder.addListener(TemplateBuilderListener);
  1063.  
  1064.   if ("arguments" in window) {
  1065.     try {
  1066.       var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
  1067.       var manager = window.arguments[1].QueryInterface(Components.interfaces.nsIObserver);
  1068.       gDownloadManager.addDownloads(params, manager);
  1069.     }
  1070.     catch (e) {
  1071.       if (window.arguments[0] == "updates-only") {
  1072.         gUpdatesOnly = true;
  1073. //@line 1115 "e:\builds\moz2_slave\win32_build\build\toolkit\mozapps\extensions\content\extensions.js"
  1074.         // If we are Firefox when updating on startup don't display context
  1075.         // menuitems that can open a browser window.
  1076.         gUpdateContextMenus = gUpdateContextMenusNoBrowser;
  1077. //@line 1119 "e:\builds\moz2_slave\win32_build\build\toolkit\mozapps\extensions\content\extensions.js"
  1078.         document.getElementById("viewGroup").hidden = true;
  1079.         document.getElementById("extensionsView").setAttribute("norestart", "");
  1080.         showView("updates");
  1081.         showMessage(URI_NOTIFICATION_ICON_INFO,
  1082.                     getExtensionString("newUpdatesAvailableMsg"),
  1083.                     null, null, true, null);
  1084.         document.title = getExtensionString("newUpdateWindowTitle", [getBrandShortName()]);
  1085.       }
  1086.       else if (window.arguments.length == 2) {
  1087.         gNewAddons = window.arguments[1].split(",");
  1088.         var installMsg = PluralForm.get(gNewAddons.length, getExtensionString("newAddonsNotificationMsg2"));
  1089.         installMsg = installMsg.replace("%S", gNewAddons.length);
  1090.         showMessage(URI_NOTIFICATION_ICON_INFO,
  1091.                     installMsg, null, null, true, null);
  1092.         var extensionCount = 0;
  1093.         var themeCount = 0;
  1094.         var localeCount = 0;
  1095.         for (var i = 0; i < gNewAddons.length; i++) {
  1096.           var item = gExtensionManager.getItemForID(gNewAddons[i]);
  1097.           switch (item.type) {
  1098.             case Components.interfaces.nsIUpdateItem.TYPE_EXTENSION:
  1099.               extensionCount++;
  1100.               break;
  1101.             case Components.interfaces.nsIUpdateItem.TYPE_THEME:
  1102.               themeCount++;
  1103.               break;
  1104.             case Components.interfaces.nsIUpdateItem.TYPE_LOCALE:
  1105.               localeCount++;
  1106.               break;
  1107.           }
  1108.         }
  1109.         if (themeCount > extensionCount && themeCount > localeCount)
  1110.           showView("themes");
  1111.         else if (localeCount > extensionCount && localeCount > themeCount)
  1112.           showView("locales");
  1113.         else
  1114.           showView("extensions");
  1115.       }
  1116.       else
  1117.         showView(window.arguments[0]);
  1118.     }
  1119.   }
  1120.   else if (viewGroup.hasAttribute("last-selected") &&
  1121.            document.getElementById(viewGroup.getAttribute("last-selected") + "-view") &&
  1122.            !document.getElementById(viewGroup.getAttribute("last-selected") + "-view").hidden)
  1123.     showView(viewGroup.getAttribute("last-selected"));
  1124.   else
  1125.     showView(gShowGetAddonsPane ? "search" : "extensions");
  1126.  
  1127.   if (gExtensionsView.selectedItem)
  1128.     gExtensionsView.scrollBoxObject.scrollToElement(gExtensionsView.selectedItem);
  1129.  
  1130.   gPref.setBoolPref(PREF_UPDATE_NOTIFYUSER, false);
  1131.  
  1132.   if (gUpdatesOnly && gExtensionsView.children.length == 0)
  1133.     window.close();
  1134. }
  1135.  
  1136. function Shutdown()
  1137. {
  1138.   gExtensionsView.builder.removeListener(TemplateBuilderListener);
  1139.  
  1140.   gPref.removeObserver(PREF_DSS_SKIN_TO_SELECT, gPrefObserver);
  1141.   gPref.removeObserver(PREF_GENERAL_SKINS_SELECTEDSKIN, gPrefObserver);
  1142.   if (gAddonRepository && gAddonRepository.isSearching)
  1143.     gAddonRepository.cancelSearch();
  1144.  
  1145.   gRDF = null;
  1146.   gPref = null;
  1147.   gExtensionsView.removeEventListener("select", onAddonSelect, false);
  1148.   gExtensionsView.database.RemoveDataSource(gExtensionManager.datasource);
  1149.  
  1150.   gExtensionManager.removeInstallListenerAt(gObserverIndex);
  1151.  
  1152.   var os = Components.classes["@mozilla.org/observer-service;1"]
  1153.                      .getService(Components.interfaces.nsIObserverService);
  1154.   os.removeObserver(gAddonsMsgObserver, "addons-message-notification");
  1155.   os.removeObserver(gDownloadManager, "xpinstall-download-started");
  1156.   os.removeObserver(gPluginObserver, "plugins-list-updated");
  1157.   var currentNotification = document.getElementById("addonsMsg").currentNotification;
  1158.   if (currentNotification && currentNotification.value == "addons-no-updates")
  1159.     window.removeEventListener("select", noUpdatesDismiss, true);
  1160. }
  1161.  
  1162. var TemplateBuilderListener = {
  1163.   willRebuild: function(aBuilder) {
  1164.   },
  1165.  
  1166.   didRebuild: function(aBuilder) {
  1167.     // Display has been rebuilt, update necessary attributes
  1168.     if (gView == "extensions" || gView == "themes" || gView == "locales") {
  1169.       for (var i = 0; i < gNewAddons.length; i++) {
  1170.         var item = document.getElementById(PREFIX_ITEM_URI + gNewAddons[i]);
  1171.         if (item)
  1172.           item.setAttribute("newAddon", "true");
  1173.       }
  1174.     }
  1175.  
  1176.     if (gView == "themes") {
  1177.       if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)) {
  1178.         var item = getItemForInternalName(gCurrentTheme);
  1179.         if (item)
  1180.           setRestartMessage(item);
  1181.       }
  1182.     }
  1183.   },
  1184.  
  1185.   QueryInterface: function (aIID)
  1186.   {
  1187.     if (!aIID.equals(Components.interfaces.nsIXULBuilderListener) &&
  1188.         !aIID.equals(Components.interfaces.nsISupports))
  1189.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1190.     return this;
  1191.   }
  1192. };
  1193.  
  1194. ///////////////////////////////////////////////////////////////////////////////
  1195. //
  1196. // XPInstall
  1197. //
  1198.  
  1199. function getURLSpecFromFile(aFile)
  1200. {
  1201.   var ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  1202.                          .getService(nsIIOService);
  1203.   var fph = ioServ.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler);
  1204.   return fph.getURLSpecFromFile(aFile);
  1205. }
  1206.  
  1207. function XPInstallDownloadManager()
  1208. {
  1209. }
  1210.  
  1211. XPInstallDownloadManager.prototype = {
  1212.   observe: function (aSubject, aTopic, aData)
  1213.   {
  1214.     switch (aTopic) {
  1215.       case "xpinstall-download-started":
  1216.         var params = aSubject.QueryInterface(Components.interfaces.nsISupportsArray);
  1217.         var paramBlock = params.GetElementAt(0).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
  1218.         paramBlock = paramBlock.data.QueryInterface(Components.interfaces.nsIDialogParamBlock);
  1219.         var manager = params.GetElementAt(1).QueryInterface(Components.interfaces.nsISupportsInterfacePointer);
  1220.         manager = manager.data.QueryInterface(Components.interfaces.nsIObserver);
  1221.         this.addDownloads(paramBlock, manager);
  1222.         break;
  1223.     }
  1224.   },
  1225.  
  1226.   addDownloads: function (aParams, aManager)
  1227.   {
  1228.     var numXPInstallItems = aParams.GetInt(1);
  1229.     var items = [];
  1230.     var switchPane = false;
  1231.     for (var i = 0; i < numXPInstallItems;) {
  1232.       var displayName = aParams.GetString(i++);
  1233.       var url = aParams.GetString(i++);
  1234.       var iconURL = aParams.GetString(i++);
  1235.       var uri = Components.classes["@mozilla.org/network/io-service;1"]
  1236.                           .getService(nsIIOService).newURI(url, null, null);
  1237.       var isTheme = uri.QueryInterface(nsIURL).fileExtension.toLowerCase() == "jar";
  1238.       if (!iconURL) {
  1239.         iconURL = isTheme ? "chrome://mozapps/skin/extensions/themeGeneric.png" :
  1240.                             "chrome://mozapps/skin/xpinstall/xpinstallItemGeneric.png";
  1241.       }
  1242.  
  1243.       var type = isTheme ? nsIUpdateItem.TYPE_THEME : nsIUpdateItem.TYPE_EXTENSION;
  1244.       var item = Components.classes["@mozilla.org/updates/item;1"]
  1245.                            .createInstance(Components.interfaces.nsIUpdateItem);
  1246.       item.init(url, " ", "app-profile", "", "", displayName, url, "", iconURL, "", "", type, "");
  1247.       items.push(item);
  1248.  
  1249.       // Advance the enumerator
  1250.       var certName = aParams.GetString(i++);
  1251.  
  1252.       // Check whether the install was triggered from the Get Add-ons pane.
  1253.       if (url in gPendingInstalls) {
  1254.         // Update the installation status
  1255.         gSearchDS.Assert(gRDF.GetResource(gPendingInstalls[url]),
  1256.                          gRDF.GetResource(PREFIX_NS_EM + "action"),
  1257.                          gRDF.GetLiteral("installing"),
  1258.                          true);
  1259.         delete gPendingInstalls[url];
  1260.       }
  1261.       else {
  1262.         switchPane = true;
  1263.       }
  1264.     }
  1265.  
  1266.     gInstalling = true;
  1267.     gExtensionManager.addDownloads(items, items.length, aManager);
  1268.     updateOptionalViews();
  1269.     updateGlobalCommands();
  1270.     // Only switch to the installs pane if there was an not started by the
  1271.     // Get Add-ons pane
  1272.     if (switchPane)
  1273.       showView("installs");
  1274.   },
  1275.  
  1276.   getElementForAddon: function(aAddon)
  1277.   {
  1278.     var element = document.getElementById(PREFIX_ITEM_URI + aAddon.id);
  1279.     if (aAddon.id == aAddon.xpiURL)
  1280.       element = document.getElementById(aAddon.xpiURL);
  1281.     return element;
  1282.   },
  1283.  
  1284.   /////////////////////////////////////////////////////////////////////////////
  1285.   // nsIAddonInstallListener
  1286.   onDownloadStarted: function(aAddon)
  1287.   {
  1288.   },
  1289.  
  1290.   onDownloadEnded: function(aAddon)
  1291.   {
  1292.   },
  1293.  
  1294.   onInstallStarted: function(aAddon)
  1295.   {
  1296.   },
  1297.   
  1298.   onCompatibilityCheckStarted: function(aAddon)
  1299.   {
  1300.   },
  1301.   
  1302.   onCompatibilityCheckEnded: function(aAddon, aStatus)
  1303.   {
  1304.   },
  1305.  
  1306.   _failed: false,
  1307.   onInstallEnded: function(aAddon, aStatus)
  1308.   {
  1309.     if (aStatus < 0)
  1310.       this._failed = true;
  1311.  
  1312.     // From nsInstall.h
  1313.     // USER_CANCELLED = -210
  1314.     // All other xpinstall errors are <= -200
  1315.     // Any errors from the EM will have been displayed directly by the EM
  1316.     if (aStatus > -200 || aStatus == -210)
  1317.       return;
  1318.  
  1319.     var xpinstallStrings = document.getElementById("xpinstallStrings");
  1320.     try {
  1321.       var msg = xpinstallStrings.getString("error" + aStatus);
  1322.     }
  1323.     catch (e) {
  1324.       msg = xpinstallStrings.getFormattedString("unknown.error", [aStatus]);
  1325.     }
  1326.     var title = getExtensionString("errorInstallTitle");
  1327.     var message = getExtensionString("errorInstallMsg", [getBrandShortName(),
  1328.                                                          aAddon.xpiURL, msg]);
  1329.     var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  1330.                        .getService(Components.interfaces.nsIPromptService);
  1331.     ps.alert(window, title, message + "\n" + aStatus);
  1332.   },
  1333.  
  1334.   onInstallsCompleted: function()
  1335.   {
  1336.     gInstalling = false;
  1337.     gExtensionManager.sortTypeByProperty(nsIUpdateItem.TYPE_ANY, "name", true);
  1338.     if (gUpdatesOnly) {
  1339.       if (this._failed) {
  1340.         let continueButton = document.getElementById("continueDialogButton");
  1341.         setElementDisabledByID("cmd_continue", false);
  1342.         continueButton.hidden = false;
  1343.         continueButton.setAttribute("default", "true");
  1344.         continueButton.focus();
  1345.       } else {
  1346.         setTimeout(closeEM, 2000);
  1347.       }
  1348.     }
  1349.     else {
  1350.       updateOptionalViews();
  1351.       updateGlobalCommands();
  1352.     }
  1353.   },
  1354.  
  1355.   _urls: { },
  1356.   onDownloadProgress: function (aAddon, aValue, aMaxValue)
  1357.   {
  1358.     var element = this.getElementForAddon(aAddon);
  1359.     if (!element)
  1360.       return;
  1361.     var percent = Math.round((aValue / aMaxValue) * 100);
  1362.     if (percent > 1 && !(aAddon.xpiURL in this._urls))
  1363.       this._urls[aAddon.xpiURL] = true;
  1364.  
  1365.     var statusPrevious = element.getAttribute("status");
  1366.     var statusCurrent = DownloadUtils.getTransferTotal(aValue, aMaxValue);
  1367.     if (statusCurrent != statusPrevious)
  1368.       element.setAttribute("status", statusCurrent);
  1369.   },
  1370.  
  1371.   /////////////////////////////////////////////////////////////////////////////
  1372.   // nsISupports
  1373.   QueryInterface: function (aIID)
  1374.   {
  1375.     if (!aIID.equals(Components.interfaces.nsIAddonInstallListener) &&
  1376.         !aIID.equals(Components.interfaces.nsISupports))
  1377.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1378.     return this;
  1379.   }
  1380. };
  1381.  
  1382. ///////////////////////////////////////////////////////////////////////////////
  1383. //
  1384. // Update Listener
  1385. //
  1386. function UpdateCheckListener() {
  1387. }
  1388. UpdateCheckListener.prototype = {
  1389.   _updateFound: false,
  1390.   _totalCount: 0,
  1391.   _completedCount: 0,
  1392.  
  1393.   /**
  1394.    * See nsIExtensionManager.idl
  1395.    */
  1396.   onUpdateStarted: function() {
  1397.     gExtensionsView.setAttribute("update-operation", "checking");
  1398.     gExtensionsViewController.onCommandUpdate();
  1399.     updateGlobalCommands();
  1400.     this._totalCount = gExtensionsView.children.length;
  1401.   },
  1402.  
  1403.   /**
  1404.    * See nsIExtensionManager.idl
  1405.    */
  1406.   onUpdateEnded: function() {
  1407.     if (!document)
  1408.       return;
  1409.     document.getElementById("progressBox").hidden = true;
  1410.     var viewGroup = document.getElementById("viewGroup");
  1411.     viewGroup.hidden = false;
  1412.     gExtensionsView.removeAttribute("update-operation");
  1413.     gExtensionsViewController.onCommandUpdate();
  1414.     updateOptionalViews();
  1415.     updateGlobalCommands();
  1416.     if (this._updateFound)
  1417.       showView("updates");
  1418.     else {
  1419.       showMessage(URI_NOTIFICATION_ICON_INFO,
  1420.                   getExtensionString("noUpdatesMsg"),
  1421.                   null, null, true, "addons-no-updates");
  1422.       window.addEventListener("select", noUpdatesDismiss, true);
  1423.     }
  1424.   },
  1425.  
  1426.   /**
  1427.    * See nsIExtensionManager.idl
  1428.    */
  1429.   onAddonUpdateStarted: function(addon) {
  1430.     if (!document)
  1431.       return;
  1432.     var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
  1433.     element.setAttribute("loading", "true");
  1434.     element.setAttribute("updateStatus", getExtensionString("updatingMsg"));
  1435.   },
  1436.  
  1437.   /**
  1438.    * See nsIExtensionManager.idl
  1439.    */
  1440.   onAddonUpdateEnded: function(addon, status) {
  1441.     if (!document)
  1442.       return;
  1443.     var element = document.getElementById(PREFIX_ITEM_URI + addon.id);
  1444.     element.removeAttribute("loading");
  1445.     const nsIAUCL = Components.interfaces.nsIAddonUpdateCheckListener;
  1446.     switch (status) {
  1447.     case nsIAUCL.STATUS_UPDATE:
  1448.       var statusMsg = getExtensionString("updateAvailableMsg", [addon.version]);
  1449.       this._updateFound = true;
  1450.       break;
  1451.     case nsIAUCL.STATUS_VERSIONINFO:
  1452.       statusMsg = getExtensionString("updateCompatibilityMsg");
  1453.       break;
  1454.     case nsIAUCL.STATUS_FAILURE:
  1455.       var name = element.getAttribute("name");
  1456.       statusMsg = getExtensionString("updateErrorMessage", [name]);
  1457.       break;
  1458.     case nsIAUCL.STATUS_DISABLED:
  1459.       name = element.getAttribute("name");
  1460.       statusMsg = getExtensionString("updateDisabledMessage", [name]);
  1461.       break;
  1462.     case nsIAUCL.STATUS_APP_MANAGED:
  1463.     case nsIAUCL.STATUS_NO_UPDATE:
  1464.       statusMsg = getExtensionString("updateNoUpdateMsg");
  1465.       break;
  1466.     case nsIAUCL.STATUS_NOT_MANAGED:
  1467.       statusMsg = getExtensionString("updateNotManagedMessage", [getBrandShortName()]);
  1468.       break;
  1469.     case nsIAUCL.STATUS_READ_ONLY:
  1470.       statusMsg = getExtensionString("updateReadOnlyMessage");
  1471.       break;
  1472.     default:
  1473.       statusMsg = getExtensionString("updateNoUpdateMsg");
  1474.     }
  1475.     element.setAttribute("updateStatus", statusMsg);
  1476.     ++this._completedCount;
  1477.     document.getElementById("progressStatus").value = getExtensionString("finishedUpdateCheck", [addon.name]);
  1478.     document.getElementById("addonsProgress").value = Math.ceil((this._completedCount / this._totalCount) * 100);
  1479.   },
  1480.  
  1481.   /**
  1482.    * See nsISupports.idl
  1483.    */
  1484.   QueryInterface: function(iid) {
  1485.     if (!iid.equals(Components.interfaces.nsIAddonUpdateCheckListener) &&
  1486.         !iid.equals(Components.interfaces.nsISupports))
  1487.       throw Components.results.NS_ERROR_NO_INTERFACE;
  1488.     return this;
  1489.   }
  1490. };
  1491.  
  1492.  
  1493. ///////////////////////////////////////////////////////////////////////////////
  1494. //
  1495. // View Event Handlers
  1496. //
  1497. function onViewDoubleClick(aEvent)
  1498. {
  1499.   if (aEvent.button != 0 || !gExtensionsView.selectedItem)
  1500.     return;
  1501.  
  1502.   switch (gView) {
  1503.     case "extensions":
  1504.       gExtensionsViewController.doCommand('cmd_options');
  1505.       break;
  1506.     case "themes":
  1507.       gExtensionsViewController.doCommand('cmd_useTheme');
  1508.       break;
  1509.     case "updates":
  1510.       gExtensionsViewController.doCommand('cmd_includeUpdate');
  1511.       break;
  1512.   }
  1513. }
  1514.  
  1515. function onAddonSelect(aEvent)
  1516. {
  1517.   var viewButton = document.getElementById("viewGroup").selectedItem;
  1518.   if (viewButton.hasAttribute("persist") && gExtensionsView.selectedItem)
  1519.     viewButton.setAttribute("last-selected", gExtensionsView.selectedItem.id);
  1520.  
  1521.   if (!document.getElementById("themePreviewArea").hidden) {
  1522.     var previewImageDeck = document.getElementById("previewImageDeck");
  1523.     if (gView == "themes") {
  1524.       var previewImage = document.getElementById("previewImage");
  1525.       if (!gExtensionsView.selectedItem) {
  1526.         previewImageDeck.selectedIndex = 0;
  1527.         if (previewImage.hasAttribute("src"))
  1528.           previewImage.removeAttribute("src");
  1529.       }
  1530.       else {
  1531.         var url = gExtensionsView.selectedItem.getAttribute("previewImage");
  1532.         if (url) {
  1533.           previewImageDeck.selectedIndex = 2;
  1534.           previewImage.setAttribute("src", url);
  1535.         }
  1536.         else {
  1537.           previewImageDeck.selectedIndex = 1;
  1538.           if (previewImage.hasAttribute("src"))
  1539.             previewImage.removeAttribute("src");
  1540.         }
  1541.       }
  1542.     }
  1543.     else if (gView == "updates") {
  1544.       UpdateInfoLoader.cancelLoad();
  1545.       if (!gExtensionsView.selectedItem) {
  1546.         previewImageDeck.selectedIndex = 3;
  1547.       }
  1548.       else {
  1549.         var uri = gExtensionsView.selectedItem.getAttribute("availableUpdateInfo");
  1550.         if (isSafeURI(uri))
  1551.           UpdateInfoLoader.loadInfo(uri);
  1552.         else
  1553.           previewImageDeck.selectedIndex = 4;
  1554.       }
  1555.     }
  1556.   }
  1557. }
  1558.  
  1559. /**
  1560.  * Manages the retrieval of update information and the xsl stylesheet
  1561.  * used to format the inforation into chrome.
  1562.  */
  1563. var UpdateInfoLoader = {
  1564.   _stylesheet: null,
  1565.   _styleRequest: null,
  1566.   _infoDocument: null,
  1567.   _infoRequest: null,
  1568.   
  1569.   // Called once both stylesheet and info requests have completed
  1570.   displayInfo: function()
  1571.   {
  1572.     var processor = Components.classes["@mozilla.org/document-transformer;1?type=xslt"]
  1573.                               .createInstance(Components.interfaces.nsIXSLTProcessor);
  1574.     processor.flags |= Components.interfaces.nsIXSLTProcessorPrivate.DISABLE_ALL_LOADS;
  1575.     
  1576.     processor.importStylesheet(this._stylesheet);
  1577.     var fragment = processor.transformToFragment(this._infoDocument, document);
  1578.     document.getElementById("infoDisplay").appendChild(fragment);
  1579.     document.getElementById("previewImageDeck").selectedIndex = 7;
  1580.   },
  1581.   
  1582.   onStylesheetLoaded: function(event)
  1583.   {
  1584.     var request = event.target;
  1585.     this._styleRequest = null;
  1586.     this._stylesheet = request.responseXML;
  1587.  
  1588.     if (!this._stylesheet ||
  1589.         this._stylesheet.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
  1590.         (request.status != 200 && request.status != 0)) {
  1591.       // The stylesheet load failing is a bad sign
  1592.       document.getElementById("previewImageDeck").selectedIndex = 6;
  1593.       return;
  1594.     }
  1595.  
  1596.     if (this._infoDocument)
  1597.       this.displayInfo();
  1598.   },
  1599.   
  1600.   onInfoLoaded: function(event)
  1601.   {
  1602.     var request = event.target;
  1603.     this._infoRequest = null;
  1604.     this._infoDocument = request.responseXML;
  1605.     
  1606.     if (!this._infoDocument ||
  1607.         this._infoDocument.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
  1608.         (request.status != 200 && request.status != 0)) {
  1609.       // Should attempt to parse request.responseText with the html parser
  1610.       document.getElementById("previewImageDeck").selectedIndex = 6;
  1611.       return;
  1612.     }
  1613.  
  1614.     if (this._stylesheet)
  1615.       this.displayInfo();
  1616.   },
  1617.   
  1618.   onError: function(event)
  1619.   {
  1620.     if (event.request == this._infoRequest)
  1621.       this._infoRequest = null;
  1622.     else // Means the stylesheet load has failed which is pretty bad news
  1623.       this.cancelRequest();
  1624.  
  1625.     document.getElementById("previewImageDeck").selectedIndex = 6;
  1626.   },
  1627.   
  1628.   loadInfo: function(url)
  1629.   {
  1630.     this.cancelLoad();
  1631.     this._infoDocument = null;
  1632.     document.getElementById("previewImageDeck").selectedIndex = 5;
  1633.     var display = document.getElementById("infoDisplay");
  1634.     while (display.lastChild)
  1635.       display.removeChild(display.lastChild);
  1636.  
  1637.     this._infoRequest = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
  1638.                                   .createInstance(Components.interfaces.nsIXMLHttpRequest);
  1639.     this._infoRequest.open("GET", url, true);
  1640.     
  1641.     var self = this;
  1642.     this._infoRequest.onerror = function(event) { self.onError(event); };
  1643.     this._infoRequest.onload = function(event) { self.onInfoLoaded(event); };
  1644.     this._infoRequest.send(null);
  1645.  
  1646.     // We may have the stylesheet cached from a previous load, or may still be
  1647.     // loading it.
  1648.     if (this._stylesheet || this._styleRequest)
  1649.       return;
  1650.  
  1651.     this._styleRequest = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
  1652.                                    .createInstance(Components.interfaces.nsIXMLHttpRequest);
  1653.     this._styleRequest.open("GET", "chrome://mozapps/content/extensions/updateinfo.xsl", true);
  1654.     this._styleRequest.overrideMimeType("text/xml");
  1655.     
  1656.     this._styleRequest.onerror = function(event) { self.onError(event); };
  1657.     this._styleRequest.onload = function(event) { self.onStylesheetLoaded(event); };
  1658.     this._styleRequest.send(null);
  1659.   },
  1660.   
  1661.   cancelLoad: function()
  1662.   {
  1663.     // Leave the stylesheet loader running, there's a good chance we'll need it
  1664.     if (this._infoRequest)
  1665.       this._infoRequest.abort();
  1666.     this._infoRequest = null;
  1667.   }
  1668. }
  1669.  
  1670. ///////////////////////////////////////////////////////////////////////////////
  1671. // View Context Menus
  1672. var gAddonContextMenus = ["menuitem_useTheme", "menuitem_options", "menuitem_homepage",
  1673.                           "menuitem_about",  "menuseparator_1", "menuitem_uninstall",
  1674.                           "menuitem_cancelUninstall", "menuitem_cancelInstall",
  1675.                           "menuitem_cancelUpgrade", "menuitem_checkUpdate",
  1676.                           "menuitem_enable", "menuitem_disable"];
  1677. var gUpdateContextMenus = ["menuitem_homepage", "menuitem_about", "menuseparator_1",
  1678.                            "menuitem_installUpdate", "menuitem_includeUpdate"];
  1679. // For Firefox don't display context menuitems that can open a browser window.
  1680. var gUpdateContextMenusNoBrowser = ["menuitem_installUpdate", "menuitem_includeUpdate"];
  1681. var gInstallContextMenus = ["menuitem_homepage", "menuitem_about", "menuseparator_1",
  1682.                             "menuitem_cancelUpgrade", "menuitem_cancelInstall"];
  1683. var gSearchContextMenus = ["menuitem_learnMore", "menuitem_installSearchResult",
  1684.                            "menuseparator_1", "menuitem_cancelInstall"];
  1685.  
  1686. function buildContextMenu(aEvent)
  1687. {
  1688.   var popup = document.getElementById("addonContextMenu");
  1689.   var selectedItem = gExtensionsView.selectedItem;
  1690.   if (aEvent.target !== popup || !selectedItem)
  1691.     return false;
  1692.  
  1693.   while (popup.hasChildNodes())
  1694.     popup.removeChild(popup.firstChild);
  1695.  
  1696.   switch (gView) {
  1697.   case "search":
  1698.     var menus = gSearchContextMenus;
  1699.     break;
  1700.   case "extensions":
  1701.   case "themes":
  1702.   case "locales":
  1703.   case "plugins":
  1704.     menus = gAddonContextMenus;
  1705.     break;
  1706.   case "updates":
  1707.     menus = gUpdateContextMenus;
  1708.     break;
  1709.   case "installs":
  1710.     menus = gInstallContextMenus;
  1711.     break;
  1712.   }
  1713.  
  1714.   for (var i = 0; i < menus.length; ++i) {
  1715.     var clonedMenu = document.getElementById(menus[i]).cloneNode(true);
  1716.     clonedMenu.id = clonedMenu.id + "_clone";
  1717.     popup.appendChild(clonedMenu);
  1718.   }
  1719.  
  1720.   // All views (but search and plugins) support about
  1721.   if (gView != "search" && gView != "plugins") {
  1722.     var menuitem_about = document.getElementById("menuitem_about_clone");
  1723.     var name = selectedItem ? selectedItem.getAttribute("name") : "";
  1724.     menuitem_about.setAttribute("label", getExtensionString("aboutAddon", [name]));
  1725.   }
  1726.  
  1727.   // Make sure all commands are up to date
  1728.   gExtensionsViewController.onCommandUpdate();
  1729.  
  1730.   // Some flags needed later
  1731.   var canCancelInstall = gExtensionsViewController.isCommandEnabled("cmd_cancelInstall");
  1732.   var canCancelUpgrade = gExtensionsViewController.isCommandEnabled("cmd_cancelUpgrade");
  1733.   var canReallyEnable = gExtensionsViewController.isCommandEnabled("cmd_reallyEnable");
  1734.   var canCancelUninstall = gExtensionsViewController.isCommandEnabled("cmd_cancelUninstall");
  1735.  
  1736.   /* When an update or install is pending allow canceling the update or install
  1737.      and don't allow uninstall. When an uninstall is pending allow canceling the
  1738.      uninstall.*/
  1739.   if (gView != "updates") {
  1740.     document.getElementById("menuitem_cancelInstall_clone").hidden = !canCancelInstall;
  1741.  
  1742.     if (gView != "installs" && gView != "search") {
  1743.       document.getElementById("menuitem_cancelUninstall_clone").hidden = !canCancelUninstall;
  1744.       document.getElementById("menuitem_uninstall_clone").hidden = canCancelUninstall ||
  1745.                                                                    canCancelInstall ||
  1746.                                                                    canCancelUpgrade;
  1747.     }
  1748.  
  1749.     if (gView != "search")
  1750.       document.getElementById("menuitem_cancelUpgrade_clone").hidden = !canCancelUpgrade;
  1751.   }
  1752.  
  1753.   switch (gView) {
  1754.   case "extensions":
  1755.     document.getElementById("menuitem_enable_clone").hidden = !canReallyEnable;
  1756.     document.getElementById("menuitem_disable_clone").hidden = canReallyEnable;
  1757.     document.getElementById("menuitem_useTheme_clone").hidden = true;
  1758.     break;
  1759.   case "themes":
  1760.     var enableMenu = document.getElementById("menuitem_enable_clone");
  1761.     if (!selectedItem.isCompatible || selectedItem.isBlocklisted ||
  1762.         !selectedItem.satisfiesDependencies || selectedItem.isDisabled)
  1763.       // don't let the user activate incompatible themes, but show a (disabled) Enable
  1764.       // menuitem to give visual feedback; it's disabled because cmd_enable returns false
  1765.       enableMenu.hidden = false;
  1766.     else
  1767.       enableMenu.hidden = true;
  1768.     document.getElementById("menuitem_options_clone").hidden = true;
  1769.     document.getElementById("menuitem_disable_clone").hidden = true;
  1770.     break;
  1771.   case "plugins":
  1772.     document.getElementById("menuitem_about_clone").hidden = true;
  1773.     document.getElementById("menuitem_uninstall_clone").hidden = true;
  1774.     document.getElementById("menuitem_checkUpdate_clone").hidden = true;
  1775.   case "locales":
  1776.     document.getElementById("menuitem_enable_clone").hidden = !canReallyEnable;
  1777.     document.getElementById("menuitem_disable_clone").hidden = canReallyEnable;
  1778.     document.getElementById("menuitem_useTheme_clone").hidden = true;
  1779.     document.getElementById("menuitem_options_clone").hidden = true;
  1780.     break;
  1781.   case "updates":
  1782.     var includeUpdate = document.getAnonymousElementByAttribute(selectedItem, "anonid", "includeUpdate");
  1783.     var menuitem_includeUpdate = document.getElementById("menuitem_includeUpdate_clone");
  1784.     menuitem_includeUpdate.setAttribute("checked", includeUpdate.checked ? "true" : "false");
  1785.     break;
  1786.   case "installs":
  1787.     // Hides the separator if nothing is below it
  1788.     document.getElementById("menuseparator_1_clone").hidden = !canCancelInstall && !canCancelUpgrade;
  1789.     break;
  1790.   case "search":
  1791.     var canInstall = gExtensionsViewController.isCommandEnabled("cmd_installSearchResult");
  1792.     document.getElementById("menuitem_installSearchResult_clone").hidden = !canInstall;
  1793.     // Hides the separator if nothing is below it
  1794.     document.getElementById("menuseparator_1_clone").hidden = !canCancelInstall;
  1795.     break;
  1796.   }
  1797.  
  1798.   return true;
  1799. }
  1800.  
  1801. ///////////////////////////////////////////////////////////////////////////////
  1802. // Drag and Drop
  1803.  
  1804. var gExtensionsDNDObserver =
  1805. {
  1806.   _ioServ: null,
  1807.   _canDrop: false,
  1808.  
  1809.   _ensureServices: function ()
  1810.   {
  1811.     if (!this._ioServ)
  1812.       this._ioServ = Components.classes["@mozilla.org/network/io-service;1"]
  1813.                                .getService(nsIIOService);
  1814.   },
  1815.  
  1816.   // returns a JS object whose properties are used by xpinstall
  1817.   _getDataFromDragSession: function (aDragSession, aPosition)
  1818.   {
  1819.     var fileData = { };
  1820.     // if this fails we do not have valid data to drop
  1821.     try {
  1822.       var xfer = Components.classes["@mozilla.org/widget/transferable;1"]
  1823.                            .createInstance(Components.interfaces.nsITransferable);
  1824.       xfer.addDataFlavor("text/x-moz-url");
  1825.       xfer.addDataFlavor("application/x-moz-file", "nsIFile");
  1826.       aDragSession.getData(xfer, aPosition);
  1827.  
  1828.       var flavour = { }, data = { }, length = { };
  1829.       xfer.getAnyTransferData(flavour, data, length);
  1830.       var selectedFlavour = this.getSupportedFlavours().flavourTable[flavour.value];
  1831.       var xferData = new FlavourData(data.value, length.value, selectedFlavour);
  1832.  
  1833.       var fileURL = transferUtils.retrieveURLFromData(xferData.data,
  1834.                                                       xferData.flavour.contentType);
  1835.       fileData.fileURL = fileURL;
  1836.  
  1837.       var uri = this._ioServ.newURI(fileURL, null, null);
  1838.       var url = uri.QueryInterface(nsIURL);
  1839.       fileData.fileName = url.fileName;
  1840.  
  1841.       switch (url.fileExtension) {
  1842.         case "xpi":
  1843.           fileData.type = nsIUpdateItem.TYPE_EXTENSION;
  1844.           break;
  1845.         case "jar":
  1846.           fileData.type = nsIUpdateItem.TYPE_THEME;
  1847.           break;
  1848.         default:
  1849.           return null;
  1850.       }
  1851.     }
  1852.     catch (e) {
  1853.       return null;
  1854.     }
  1855.  
  1856.     return fileData;
  1857.   },
  1858.  
  1859.   canDrop: function (aEvent, aDragSession) { return this._canDrop; },
  1860.  
  1861.   onDragEnter: function (aEvent, aDragSession)
  1862.   {
  1863.     // XXXrstrong - bug 269568, GTK2 drag and drop is returning invalid data for
  1864.     // dragenter and dragover. To workaround this we always set canDrop to true
  1865.     // and just use the xfer data returned in ondrop which is valid.
  1866. //@line 1908 "e:\builds\moz2_slave\win32_build\build\toolkit\mozapps\extensions\content\extensions.js"
  1867.     this._ensureServices();
  1868.  
  1869.     var count = aDragSession.numDropItems;
  1870.     for (var i = 0; i < count; ++i) {
  1871.       var fileData = this._getDataFromDragSession(aDragSession, i);
  1872.       if (!fileData) {
  1873.         this._canDrop = false;
  1874.         return;
  1875.       }
  1876.     }
  1877. //@line 1919 "e:\builds\moz2_slave\win32_build\build\toolkit\mozapps\extensions\content\extensions.js"
  1878.     this._canDrop = true;
  1879.   },
  1880.  
  1881.   onDragOver: function (aEvent, aFlavor, aDragSession) { },
  1882.  
  1883.   onDrop: function(aEvent, aXferData, aDragSession)
  1884.   {
  1885.     if (!isXPInstallEnabled())
  1886.       return;
  1887.  
  1888.     this._ensureServices();
  1889.  
  1890.     var xpinstallObj = { };
  1891.     var themes = { };
  1892.     var xpiCount = 0;
  1893.     var themeCount = 0;
  1894.  
  1895.     var count = aDragSession.numDropItems;
  1896.     for (var i = 0; i < count; ++i) {
  1897.       var fileData = this._getDataFromDragSession(aDragSession, i);
  1898.       if (!fileData)
  1899.         continue;
  1900.  
  1901.       xpinstallObj[fileData.fileName] = {
  1902.         URL: fileData.fileURL,
  1903.         toString: function() { return this.URL; }
  1904.       };
  1905.       ++xpiCount;
  1906.       if (fileData.type == nsIUpdateItem.TYPE_THEME)
  1907.         xpinstallObj[fileData.fileName].IconURL = URI_GENERIC_ICON_THEME;
  1908.       else
  1909.         xpinstallObj[fileData.fileName].IconURL = URI_GENERIC_ICON_XPINSTALL;
  1910.     }
  1911.  
  1912.     if (xpiCount > 0)
  1913.       InstallTrigger.install(xpinstallObj);
  1914.   },
  1915.   _flavourSet: null,
  1916.   getSupportedFlavours: function ()
  1917.   {
  1918.     if (!this._flavourSet) {
  1919.       this._flavourSet = new FlavourSet();
  1920.       this._flavourSet.appendFlavour("text/x-moz-url");
  1921.       this._flavourSet.appendFlavour("application/x-moz-file", "nsIFile");
  1922.     }
  1923.     return this._flavourSet;
  1924.   }
  1925. };
  1926.  
  1927. ///////////////////////////////////////////////////////////////////////////////
  1928. // Notification Messages
  1929. const gAddonsMsgObserver = {
  1930.   observe: function (aSubject, aTopic, aData)
  1931.   {
  1932.     switch (aData) {
  1933.     case "addons-enable-xpinstall":
  1934.       gPref.setBoolPref("xpinstall.enabled", true);
  1935.       break;
  1936.     case "addons-enable-compatibility":
  1937.       gPref.clearUserPref(PREF_EM_CHECK_COMPATIBILITY);
  1938.       gCheckCompat = true;
  1939.       break;
  1940.     case "addons-enable-updatesecurity":
  1941.       gPref.clearUserPref(PREF_EM_CHECK_UPDATE_SECURITY);
  1942.       gCheckUpdateSecurity = true;
  1943.       break;
  1944.     case "addons-no-updates":
  1945.       var children = gExtensionsView.children;
  1946.       for (var i = 0; i < children.length; ++i) {
  1947.         var child = children[i];
  1948.         if (child.hasAttribute("updateStatus"))
  1949.           child.removeAttribute("updateStatus");
  1950.       }
  1951.       break;
  1952.     case "addons-go-online":
  1953.       var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  1954.                                 .getService(nsIIOService);
  1955.       ioService.offline = false;
  1956.       // If no results have been retrieved start pulling some
  1957.       if (!gRetrievedResults)
  1958.         retrieveRepositoryAddons(document.getElementById("searchfield").value);
  1959.       if (gView == "search")
  1960.         document.getElementById("searchfield").disabled = false;
  1961.       break;
  1962.     case "addons-message-dismiss":
  1963.       break;
  1964.     case "addons-restart-app":
  1965.       restartApp();
  1966.       break;
  1967.     }
  1968.     if (gExtensionsView.selectedItem)
  1969.       gExtensionsView.selectedItem.focus();
  1970.   }
  1971. };
  1972.  
  1973. const gPrefObserver = {
  1974.   observe: function (aSubject, aTopic, aData)
  1975.   {
  1976.     if (aData == PREF_GENERAL_SKINS_SELECTEDSKIN) {
  1977.       // Changed as the result of a dynamic theme switch
  1978.       gCurrentTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  1979.     }
  1980.     else if (aData == PREF_DSS_SKIN_TO_SELECT) {
  1981.       // Either a new skin has been selected or the switch has been cancelled
  1982.       if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING))
  1983.         gCurrentTheme = gPref.getCharPref(PREF_DSS_SKIN_TO_SELECT);
  1984.       else
  1985.         gCurrentTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  1986.       updateOptionalViews();
  1987.       updateGlobalCommands();
  1988.     }
  1989.   }
  1990. };
  1991.  
  1992. const gPluginObserver = {
  1993.   observe: function (aSubject, aTopic, aData)
  1994.   {
  1995.     rebuildPluginsDS();
  1996.   }
  1997. };
  1998.  
  1999. function isXPInstallEnabled() {
  2000.   var enabled = false;
  2001.   var locked = false;
  2002.   try {
  2003.     enabled = gPref.getBoolPref("xpinstall.enabled");
  2004.     if (enabled)
  2005.       return true;
  2006.     locked = gPref.prefIsLocked("xpinstall.enabled");
  2007.   }
  2008.   catch (e) { }
  2009.  
  2010.   var msgText = getExtensionString(locked ? "xpinstallDisabledMsgLocked" :
  2011.                                             "xpinstallDisabledMsg");
  2012.   var buttonLabel = locked ? null : getExtensionString("enableButtonLabel");
  2013.   var buttonAccesskey = locked ? null : getExtensionString("enableButtonAccesskey");
  2014.   var notifyData = locked ? null : "addons-enable-xpinstall";
  2015.   showMessage(URI_NOTIFICATION_ICON_WARNING,
  2016.               msgText, buttonLabel, buttonAccesskey,
  2017.               !locked, notifyData);
  2018.   return false;
  2019. }
  2020.  
  2021. function isOffline(messageKey) {
  2022.   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  2023.                             .getService(nsIIOService);
  2024.   if (ioService.offline) {
  2025.     showMessage(URI_NOTIFICATION_ICON_WARNING,
  2026.                 getExtensionString(messageKey, [getBrandShortName()]),
  2027.                 getExtensionString("goOnlineButtonLabel"),
  2028.                 getExtensionString("goOnlineButtonAccesskey"),
  2029.                 true, "addons-go-online");
  2030.   }
  2031.   return ioService.offline;
  2032. }
  2033.  
  2034. ///////////////////////////////////////////////////////////////////////////////
  2035. // Command Updating and Command Handlers
  2036.  
  2037. function canWriteToLocation(element)
  2038. {
  2039.   var installLocation = null;
  2040.   if (element) {
  2041.     var id = getIDFromResourceURI(element.id)
  2042.     installLocation = gExtensionManager.getInstallLocation(id);
  2043.   }
  2044.   return installLocation ? installLocation.canAccess : false;
  2045. }
  2046.  
  2047. function enableRestartButton() {
  2048.   var addonsMsg = document.getElementById("addonsMsg");
  2049.   var notification = addonsMsg.getNotificationWithValue("restart-app");
  2050.   if (!notification) {
  2051.     var appname = getBrandShortName();
  2052.     var message = getExtensionString("restartMessage", [appname]);
  2053.     var buttons = [ new MessageButton(getExtensionString("restartButton", [appname]),
  2054.                                       getExtensionString("restartAccessKey"),
  2055.                                       "addons-restart-app") ];
  2056.     addonsMsg.appendNotification(message, "restart-app",
  2057.                                  URI_NOTIFICATION_ICON_INFO,
  2058.                                  addonsMsg.PRIORITY_WARNING_HIGH, buttons);
  2059.   }
  2060. }
  2061.  
  2062. function disableRestartButton() {
  2063.   var addonsMsg = document.getElementById("addonsMsg");
  2064.   var notification = addonsMsg.getNotificationWithValue("restart-app");
  2065.   if (notification)
  2066.     notification.close();
  2067. }
  2068.  
  2069. function updateOptionalViews() {
  2070.   var ds = gExtensionsView.database;
  2071.   var ctr = Components.classes["@mozilla.org/rdf/container;1"]
  2072.                       .createInstance(Components.interfaces.nsIRDFContainer);
  2073.   ctr.Init(ds, gRDF.GetResource(RDFURI_ITEM_ROOT));
  2074.   var elements = ctr.GetElements();
  2075.   var showLocales = false;
  2076.   var showUpdates = false;
  2077.   var showThemes = false;
  2078.   var showInstalls = gInstalling;
  2079.   gPendingActions = false;
  2080.  
  2081.   var stateArc = gRDF.GetResource(PREFIX_NS_EM + "state");
  2082.   var opTypeArc = gRDF.GetResource(PREFIX_NS_EM + "opType");
  2083.  
  2084.   while (elements.hasMoreElements()) {
  2085.     var e = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
  2086.     if (!showLocales || !showThemes) {
  2087.       var typeArc = gRDF.GetResource(PREFIX_NS_EM + "type");
  2088.       var type = ds.GetTarget(e, typeArc, true);
  2089.       if (type && type instanceof Components.interfaces.nsIRDFInt) {
  2090.         if (type.Value & nsIUpdateItem.TYPE_LOCALE)
  2091.           showLocales = true;
  2092.         else if (type.Value & nsIUpdateItem.TYPE_THEME)
  2093.           showThemes = true;
  2094.       }
  2095.     }
  2096.  
  2097.     if (!gInstalling || !showInstalls) {
  2098.       var state = ds.GetTarget(e, stateArc, true);
  2099.       if (state) {
  2100.         showInstalls = true;
  2101.         if (state instanceof Components.interfaces.nsIRDFLiteral &&
  2102.             state.Value != "success" && state.Value != "failure")
  2103.           gInstalling = true;
  2104.       }
  2105.     }
  2106.  
  2107.     if (!gPendingActions) {
  2108.       var opType = ds.GetTarget(e, opTypeArc, true);
  2109.       if (opType) {
  2110.         if (opType instanceof Components.interfaces.nsIRDFLiteral &&
  2111.             opType.Value != OP_NONE)
  2112.           gPendingActions = true;
  2113.       }
  2114.     }
  2115.  
  2116.     if (!showUpdates) {
  2117.       var updateURLArc = gRDF.GetResource(PREFIX_NS_EM + "availableUpdateURL");
  2118.       var updateURL = ds.GetTarget(e, updateURLArc, true);
  2119.       if (updateURL) {
  2120.         var updateableArc = gRDF.GetResource(PREFIX_NS_EM + "updateable");
  2121.         var updateable = ds.GetTarget(e, updateableArc, true);
  2122.         updateable = updateable.QueryInterface(Components.interfaces.nsIRDFLiteral);
  2123.         if (updateable.Value == "true")
  2124.           showUpdates = true;
  2125.       }
  2126.     }
  2127.   }
  2128.  
  2129.   document.getElementById("locales-view").hidden = !showLocales;
  2130.   document.getElementById("updates-view").hidden = !showUpdates;
  2131.   document.getElementById("installs-view").hidden = !showInstalls;
  2132.   document.getElementById("themes-view").hidden = !showThemes;
  2133.   updateVisibilityFlags();
  2134.  
  2135.   // fall back to the previously selected view or "search" since "installs" became hidden
  2136.   if (!showInstalls && gView == "installs") {
  2137.     var viewGroup = document.getElementById("viewGroup");
  2138.     var lastSelectedView = "search";
  2139.  
  2140.     if (viewGroup.hasAttribute("last-selected"))
  2141.       lastSelectedView = viewGroup.getAttribute("last-selected");
  2142.  
  2143.     showView(lastSelectedView);
  2144.   }
  2145. }
  2146.  
  2147. function updateVisibilityFlags() {
  2148.   let children = document.getElementById("installs-view").parentNode._getRadioChildren();
  2149.   let firstVisible = null, lastVisible = null;
  2150.   children.forEach(function(child) {
  2151.     child.removeAttribute("first-visible");
  2152.     child.removeAttribute("last-visible");
  2153.     if (!child.hidden) {
  2154.       firstVisible = firstVisible || child;
  2155.       lastVisible = child;
  2156.     }
  2157.   });
  2158.   if (firstVisible) {
  2159.     firstVisible.setAttribute("first-visible", "true");
  2160.     lastVisible.setAttribute("last-visible", "true");
  2161.   }
  2162. }
  2163.  
  2164. function updateGlobalCommands() {
  2165.   var disableInstallFile = false;
  2166.   var disableUpdateCheck = true;
  2167.   var disableInstallUpdate = true;
  2168.  
  2169.   if (gExtensionsView.hasAttribute("update-operation")) {
  2170.     disableInstallFile = true;
  2171.     disableRestartButton();
  2172.   }
  2173.   else if (gView == "updates") {
  2174.     disableInstallUpdate = false;
  2175.     disableRestartButton();
  2176.   }
  2177.   else {
  2178.     var children = gExtensionsView.children;
  2179.     for (var i = 0; i < children.length; ++i) {
  2180.       if (children[i].getAttribute("updateable") == "true") {
  2181.         disableUpdateCheck = false;
  2182.         break;
  2183.       }
  2184.     }
  2185.  
  2186.     if (!gInstalling &&
  2187.         (gPendingActions || gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)))
  2188.       enableRestartButton();
  2189.     else
  2190.       disableRestartButton();
  2191.   }
  2192.  
  2193.   setElementDisabledByID("cmd_checkUpdatesAll", disableUpdateCheck);
  2194.   setElementDisabledByID("cmd_installUpdatesAll", disableInstallUpdate);
  2195.   setElementDisabledByID("cmd_installFile", disableInstallFile);
  2196. }
  2197.  
  2198. function showUpdateInfo()
  2199. {
  2200.   document.getElementById("themePreviewArea").hidden = false;
  2201.   document.getElementById("themeSplitter").hidden = false;
  2202.   document.getElementById("showUpdateInfoButton").hidden = true;
  2203.   document.getElementById("hideUpdateInfoButton").hidden = false;
  2204.   onAddonSelect();
  2205. }
  2206.  
  2207. function hideUpdateInfo()
  2208. {
  2209.   UpdateInfoLoader.cancelLoad();
  2210.   document.getElementById("themePreviewArea").hidden = true;
  2211.   document.getElementById("themeSplitter").hidden = true;
  2212.   document.getElementById("showUpdateInfoButton").hidden = false;
  2213.   document.getElementById("hideUpdateInfoButton").hidden = true;
  2214. }
  2215.  
  2216. function checkUpdatesAll() {
  2217.   if (isOffline("offlineUpdateMsg2"))
  2218.     return;
  2219.  
  2220.   if (!isXPInstallEnabled())
  2221.     return;
  2222.  
  2223.   // To support custom views we check the add-ons displayed in the list
  2224.   var items = [];
  2225.   var children = gExtensionsView.children;
  2226.   for (var i = 0; i < children.length; ++i) {
  2227.     if (children[i].getAttribute("updateable") != "false")
  2228.       items.push(gExtensionManager.getItemForID(getIDFromResourceURI(children[i].id)));
  2229.   }
  2230.  
  2231.   if (items.length > 0) {
  2232.     showProgressBar();
  2233.     var listener = new UpdateCheckListener();
  2234.     gExtensionManager.update(items, items.length,
  2235.                              nsIExtensionManager.UPDATE_CHECK_NEWVERSION,
  2236.                              listener);
  2237.   }
  2238.   if (gExtensionsView.selectedItem)
  2239.     gExtensionsView.selectedItem.focus();
  2240.  
  2241.   gPref.setBoolPref(PREF_UPDATE_NOTIFYUSER, false);
  2242. }
  2243.  
  2244. function installUpdatesAll() {
  2245.   if (isOffline("offlineUpdateMsg2"))
  2246.     return;
  2247.  
  2248.   if (!isXPInstallEnabled())
  2249.     return;
  2250.  
  2251.   if (gUpdatesOnly) {
  2252.     var notifications = document.getElementById("addonsMsg");
  2253.     if (notifications.currentNotification)
  2254.       notifications.removeCurrentNotification();
  2255.   }
  2256.  
  2257.   var items = [];
  2258.   var children = gExtensionsView.children;
  2259.   for (var i = 0; i < children.length; ++i) {
  2260.     var includeUpdate = document.getAnonymousElementByAttribute(children[i], "anonid", "includeUpdate");
  2261.     if (includeUpdate && includeUpdate.checked)
  2262.       items.push(gExtensionManager.getItemForID(getIDFromResourceURI(children[i].id)));
  2263.   }
  2264.   if (items.length > 0) {
  2265.     gInstalling = true;
  2266.     gExtensionManager.addDownloads(items, items.length, null);
  2267.     showView("installs");
  2268.     // Remove the updates view if there are no add-ons left to update
  2269.     updateOptionalViews();
  2270.     updateGlobalCommands();
  2271.   }
  2272. }
  2273.  
  2274. function restartApp() {
  2275.  
  2276.   // Notify all windows that an application quit has been requested.
  2277.   var os = Components.classes["@mozilla.org/observer-service;1"]
  2278.                      .getService(Components.interfaces.nsIObserverService);
  2279.   var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
  2280.                              .createInstance(Components.interfaces.nsISupportsPRBool);
  2281.   os.notifyObservers(cancelQuit, "quit-application-requested", "restart");
  2282.  
  2283.   // Something aborted the quit process.
  2284.   if (cancelQuit.data)
  2285.     return;
  2286.  
  2287.   Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(nsIAppStartup)
  2288.             .quit(nsIAppStartup.eRestart | nsIAppStartup.eAttemptQuit);
  2289. }
  2290.  
  2291. function installWithFilePicker() {
  2292.   if (!isXPInstallEnabled())
  2293.     return;
  2294.  
  2295.   if (gView == "themes")
  2296.     installSkin();
  2297.   else
  2298.     installExtension();
  2299. }
  2300.  
  2301. function closeEM() {
  2302.   closeWindow(true);
  2303. }
  2304.  
  2305. function confirmOperation(aName, aTitle, aQueryMsg, aAcceptBtn, aCancelBtn,
  2306.                           aWarnMsg, aDependantItems) {
  2307.   var params = {
  2308.     message2: getExtensionString(aQueryMsg, [aName]),
  2309.     title: getExtensionString(aTitle, [aName]),
  2310.     buttons: {
  2311.       accept: { label: getExtensionString(aAcceptBtn) },
  2312.       cancel: { label: getExtensionString(aCancelBtn), focused: true }
  2313.     }
  2314.   }
  2315.   if (aDependantItems.length > 0)
  2316.     params.message1 = getExtensionString(aWarnMsg, [aName]);
  2317.   var names = [];
  2318.   for (var i = 0; i < aDependantItems.length; ++i)
  2319.     names.push(aDependantItems[i].name + " " + aDependantItems[i].version);
  2320.  
  2321.   window.openDialog("chrome://mozapps/content/extensions/list.xul", "",
  2322.                     "titlebar,modal,centerscreen", names, params);
  2323.   return params.result == "accept";
  2324. }
  2325.  
  2326. function installCallback(item, status) {
  2327.   var resultNode = gRDF.GetResource(item.id);
  2328.   var actionArc = gRDF.GetResource(PREFIX_NS_EM + "action");
  2329.  
  2330.   // Strip out old status
  2331.   var targets = gSearchDS.GetTargets(resultNode, actionArc, true);
  2332.   while (targets.hasMoreElements()) {
  2333.     var value = targets.getNext().QueryInterface(Components.interfaces.nsIRDFNode);
  2334.     if (value)
  2335.       gSearchDS.Unassert(resultNode, actionArc, value);
  2336.   }
  2337.  
  2338.   if (status == -210) {
  2339.     // User cancelled
  2340.     if (item.getAttribute("xpiURL") in gPendingInstalls)
  2341.       delete gPendingInstalls[item.getAttribute("xpiURL")];
  2342.     return;
  2343.   }
  2344.   if (status < 0) {
  2345.     // Some other failure
  2346.     gSearchDS.Assert(resultNode,
  2347.                      actionArc,
  2348.                      gRDF.GetLiteral("failed"),
  2349.                      true);
  2350.   }
  2351.   else {
  2352.     // Success
  2353.     gSearchDS.Assert(resultNode,
  2354.                      actionArc,
  2355.                      gRDF.GetLiteral("installed"),
  2356.                      true);
  2357.   }
  2358. }
  2359.  
  2360. var gExtensionsViewController = {
  2361.   supportsCommand: function (aCommand)
  2362.   {
  2363.     var commandNode = document.getElementById(aCommand);
  2364.     return commandNode && (commandNode.parentNode == document.getElementById("extensionsCommands"));
  2365.   },
  2366.  
  2367.   isCommandEnabled: function (aCommand)
  2368.   {
  2369.     var selectedItem = gExtensionsView.selectedItem;
  2370.     if (!selectedItem)
  2371.       return false;
  2372.  
  2373.     if (selectedItem.hasAttribute("downloadURL") &&
  2374.         selectedItem.getAttribute("downloadURL") != "") {
  2375.       if (aCommand == "cmd_uninstall")
  2376.         return true;
  2377.       return false;
  2378.     }
  2379.     switch (aCommand) {
  2380.     case "cmd_installSearchResult":
  2381.       return selectedItem.getAttribute("action") == "" ||
  2382.              selectedItem.getAttribute("action") == "failed";
  2383.     case "cmd_useTheme":
  2384.       return selectedItem.type == nsIUpdateItem.TYPE_THEME &&
  2385.              !selectedItem.isDisabled &&
  2386.              selectedItem.opType != OP_NEEDS_UNINSTALL &&
  2387.              gCurrentTheme != selectedItem.getAttribute("internalName");
  2388.     case "cmd_options":
  2389.       return selectedItem.type == nsIUpdateItem.TYPE_EXTENSION &&
  2390.              !selectedItem.isDisabled &&
  2391.              !gInSafeMode &&
  2392.              !selectedItem.opType &&
  2393.              selectedItem.getAttribute("optionsURL") != "";
  2394.     case "cmd_about":
  2395.       return selectedItem.opType != OP_NEEDS_INSTALL &&
  2396.              selectedItem.getAttribute("plugin") != "true";
  2397.     case "cmd_homepage":
  2398.       return selectedItem.getAttribute("homepageURL") != "";
  2399.     case "cmd_uninstall":
  2400.       return (selectedItem.type != nsIUpdateItem.TYPE_THEME ||
  2401.              selectedItem.type == nsIUpdateItem.TYPE_THEME &&
  2402.              selectedItem.getAttribute("internalName") != gDefaultTheme) &&
  2403.              selectedItem.opType != OP_NEEDS_UNINSTALL &&
  2404.              selectedItem.getAttribute("locked") != "true" &&
  2405.              canWriteToLocation(selectedItem) &&
  2406.              !gExtensionsView.hasAttribute("update-operation");
  2407.     case "cmd_cancelUninstall":
  2408.       return selectedItem.opType == OP_NEEDS_UNINSTALL;
  2409.     case "cmd_cancelInstall":
  2410.       return selectedItem.getAttribute("action") == "installed" &&
  2411.              gView == "search" || selectedItem.opType == OP_NEEDS_INSTALL;
  2412.     case "cmd_cancelUpgrade":
  2413.       return selectedItem.opType == OP_NEEDS_UPGRADE;
  2414.     case "cmd_checkUpdate":
  2415.       return selectedItem.getAttribute("updateable") != "false" &&
  2416.              !gExtensionsView.hasAttribute("update-operation");
  2417.     case "cmd_installUpdate":
  2418.       return selectedItem.hasAttribute("availableUpdateURL") &&
  2419.              !gExtensionsView.hasAttribute("update-operation");
  2420.     case "cmd_includeUpdate":
  2421.       return selectedItem.hasAttribute("availableUpdateURL") &&
  2422.              !gExtensionsView.hasAttribute("update-operation");
  2423.     case "cmd_reallyEnable":
  2424.     // controls whether to show Enable or Disable in extensions' context menu
  2425.       return selectedItem.isDisabled &&
  2426.              selectedItem.opType != OP_NEEDS_ENABLE ||
  2427.              selectedItem.opType == OP_NEEDS_DISABLE;
  2428.     case "cmd_enable":
  2429.       return selectedItem.type != nsIUpdateItem.TYPE_THEME &&
  2430.              (selectedItem.isDisabled ||
  2431.              (!selectedItem.opType ||
  2432.              selectedItem.opType == OP_NEEDS_DISABLE)) &&
  2433.              !selectedItem.isBlocklisted &&
  2434.              (!gCheckUpdateSecurity || selectedItem.providesUpdatesSecurely) &&
  2435.              (!gCheckCompat || selectedItem.isCompatible) &&
  2436.              selectedItem.satisfiesDependencies &&
  2437.              !gExtensionsView.hasAttribute("update-operation");
  2438.     case "cmd_disable":
  2439.       return selectedItem.type != nsIUpdateItem.TYPE_THEME &&
  2440.              (!selectedItem.isDisabled &&
  2441.              !selectedItem.opType ||
  2442.              selectedItem.opType == OP_NEEDS_ENABLE) &&
  2443.              !selectedItem.isBlocklisted &&
  2444.              selectedItem.satisfiesDependencies &&
  2445.              !gExtensionsView.hasAttribute("update-operation");
  2446.     }
  2447.     return false;
  2448.   },
  2449.  
  2450.   doCommand: function (aCommand)
  2451.   {
  2452.     if (this.isCommandEnabled(aCommand))
  2453.       this.commands[aCommand](gExtensionsView.selectedItem);
  2454.   },
  2455.  
  2456.   onCommandUpdate: function ()
  2457.   {
  2458.     var extensionsCommands = document.getElementById("extensionsCommands");
  2459.     for (var i = 0; i < extensionsCommands.childNodes.length; ++i)
  2460.       this.updateCommand(extensionsCommands.childNodes[i]);
  2461.   },
  2462.  
  2463.   updateCommand: function (command)
  2464.   {
  2465.     if (this.isCommandEnabled(command.id))
  2466.       command.removeAttribute("disabled");
  2467.     else
  2468.       command.setAttribute("disabled", "true");
  2469.   },
  2470.  
  2471.   commands: {
  2472.     cmd_installSearchResult: function (aSelectedItem)
  2473.     {
  2474.       if (!isXPInstallEnabled())
  2475.         return;
  2476.  
  2477.       if (aSelectedItem.hasAttribute("eula")) {
  2478.         var eula = {
  2479.           name: aSelectedItem.getAttribute("name"),
  2480.           text: aSelectedItem.getAttribute("eula"),
  2481.           accepted: false
  2482.         };
  2483.         window.openDialog("chrome://mozapps/content/extensions/eula.xul", "_blank",
  2484.                           "chrome,dialog,modal,centerscreen,resizable=no", eula);
  2485.         if (!eula.accepted)
  2486.           return;
  2487.       }
  2488.  
  2489.       var details = {
  2490.         URL: aSelectedItem.getAttribute("xpiURL"),
  2491.         Hash: aSelectedItem.getAttribute("xpiHash"),
  2492.         IconURL: aSelectedItem.getAttribute("iconURL"),
  2493.         toString: function () { return this.URL; }
  2494.       };
  2495.       var params = [];
  2496.       params[aSelectedItem.getAttribute("name")] = details;
  2497.  
  2498.       gSearchDS.Assert(gRDF.GetResource(aSelectedItem.id),
  2499.                        gRDF.GetResource(PREFIX_NS_EM + "action"),
  2500.                        gRDF.GetLiteral("connecting"),
  2501.                        true);
  2502.       // Remember this install so we can update the status when install starts
  2503.       gPendingInstalls[details.URL] = aSelectedItem.id;
  2504.       InstallTrigger.install(params, function(url, status) { installCallback(aSelectedItem, status); });
  2505.     },
  2506.  
  2507.     cmd_close: function (aSelectedItem)
  2508.     {
  2509.       closeWindow(true);
  2510.     },
  2511.  
  2512.     cmd_useTheme: function (aSelectedItem)
  2513.     {
  2514.       gCurrentTheme = aSelectedItem.getAttribute("internalName");
  2515.  
  2516.       // If choosing the current skin just reset the pending change
  2517.       if (gCurrentTheme == gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN)) {
  2518.         gPref.clearUserPref(PREF_EXTENSIONS_DSS_SWITCHPENDING);
  2519.         gPref.clearUserPref(PREF_DSS_SKIN_TO_SELECT);
  2520.         clearRestartMessage();
  2521.       }
  2522.       else {
  2523.         if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_ENABLED)) {
  2524.           gPref.setCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN, gCurrentTheme);
  2525.         }
  2526.         else {
  2527.           // Theme change will happen on next startup, this flag tells
  2528.           // the Theme Manager that it needs to show "This theme will
  2529.           // be selected after a restart" text in the selected theme
  2530.           // item.
  2531.           gPref.setBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING, true);
  2532.           gPref.setCharPref(PREF_DSS_SKIN_TO_SELECT, gCurrentTheme);
  2533.           clearRestartMessage();
  2534.           setRestartMessage(aSelectedItem);
  2535.         }
  2536.       }
  2537.  
  2538.       // Flush preference change to disk
  2539.       gPref.QueryInterface(Components.interfaces.nsIPrefService)
  2540.            .savePrefFile(null);
  2541.  
  2542.       // disable the useThemeButton
  2543.       gExtensionsViewController.onCommandUpdate();
  2544.     },
  2545.  
  2546.     cmd_options: function (aSelectedItem)
  2547.     {
  2548.       if (!aSelectedItem) return;
  2549.       var optionsURL = aSelectedItem.getAttribute("optionsURL");
  2550.       if (optionsURL == "")
  2551.         return;
  2552.  
  2553.       var windows = Components.classes['@mozilla.org/appshell/window-mediator;1']
  2554.                               .getService(Components.interfaces.nsIWindowMediator)
  2555.                               .getEnumerator(null);
  2556.       while (windows.hasMoreElements()) {
  2557.         var win = windows.getNext();
  2558.         if (win.document.documentURI == optionsURL) {
  2559.           win.focus();
  2560.           return;
  2561.         }
  2562.       }
  2563.  
  2564.       var features;
  2565.       try {
  2566.         var instantApply = gPref.getBoolPref("browser.preferences.instantApply");
  2567.         features = "chrome,titlebar,toolbar,centerscreen" + (instantApply ? ",dialog=no" : ",modal");
  2568.       }
  2569.       catch (e) {
  2570.         features = "chrome,titlebar,toolbar,centerscreen,modal";
  2571.       }
  2572.       openDialog(optionsURL, "", features);
  2573.     },
  2574.  
  2575.     cmd_homepage: function (aSelectedItem)
  2576.     {
  2577.       if (!aSelectedItem) return;
  2578.       var homepageURL = aSelectedItem.getAttribute("homepageURL");
  2579.       // only allow http(s) homepages
  2580.       if (isSafeURI(homepageURL))
  2581.         openURL(homepageURL);
  2582.     },
  2583.  
  2584.     cmd_about: function (aSelectedItem)
  2585.     {
  2586.       if (!aSelectedItem) return;
  2587.       var aboutURL = aSelectedItem.getAttribute("aboutURL");
  2588.       if (aboutURL != "")
  2589.         openDialog(aboutURL, "", "chrome,centerscreen,modal");
  2590.       else
  2591.         openDialog("chrome://mozapps/content/extensions/about.xul", "", "chrome,centerscreen,modal", aSelectedItem.id, gExtensionsView.database);
  2592.     },
  2593.  
  2594.     cmd_checkUpdate: function (aSelectedItem)
  2595.     {
  2596.       if (isOffline("offlineUpdateMsg2"))
  2597.         return;
  2598.  
  2599.       if (!isXPInstallEnabled())
  2600.         return;
  2601.  
  2602.       var id = getIDFromResourceURI(aSelectedItem.id);
  2603.       var items = [gExtensionManager.getItemForID(id)];
  2604.       var listener = new UpdateCheckListener();
  2605.       gExtensionManager.update(items, items.length,
  2606.                                nsIExtensionManager.UPDATE_CHECK_NEWVERSION,
  2607.                                listener);
  2608.     },
  2609.  
  2610.     cmd_installUpdate: function (aSelectedItem)
  2611.     {
  2612.       if (isOffline("offlineUpdateMsg2"))
  2613.         return;
  2614.  
  2615.       if (!isXPInstallEnabled())
  2616.         return;
  2617.  
  2618.       showView("installs");
  2619.       var item = gExtensionManager.getItemForID(getIDFromResourceURI(aSelectedItem.id));
  2620.       gInstalling = true;
  2621.       gExtensionManager.addDownloads([item], 1, null);
  2622.       // Remove the updates view if there are no add-ons left to update
  2623.       updateOptionalViews();
  2624.       updateGlobalCommands();
  2625.     },
  2626.  
  2627.     cmd_includeUpdate: function (aSelectedItem)
  2628.     {
  2629.       var includeUpdate = document.getAnonymousElementByAttribute(aSelectedItem, "anonid", "includeUpdate");
  2630.       includeUpdate.checked = !includeUpdate.checked;
  2631.     },
  2632.  
  2633.     cmd_uninstall: function (aSelectedItem)
  2634.     {
  2635.       // Confirm the uninstall
  2636.       var name = aSelectedItem.getAttribute("name");
  2637.       var id = getIDFromResourceURI(aSelectedItem.id);
  2638.       var dependentItems = gExtensionManager.getDependentItemListForID(id, true, { });
  2639.       var result = confirmOperation(name, "uninstallTitle", "uninstallQueryMessage",
  2640.                                     "uninstallButton", "cancelButton",
  2641.                                     "uninstallWarnDependMsg", dependentItems);
  2642.       if (!result)
  2643.         return;
  2644.  
  2645.       if (aSelectedItem.type == nsIUpdateItem.TYPE_THEME) {
  2646.         var theme = aSelectedItem.getAttribute("internalName");
  2647.         var selectedTheme = gPref.getCharPref(PREF_GENERAL_SKINS_SELECTEDSKIN);
  2648.         if (theme == gCurrentTheme) {
  2649.           if (gPref.getBoolPref(PREF_EXTENSIONS_DSS_SWITCHPENDING)) {
  2650.             var item = getItemForInternalName(selectedTheme);
  2651.             if (item && item.getAttribute("opType") == OP_NEEDS_UNINSTALL) {
  2652.               // We're uninstalling the theme to be switched to, but the current
  2653.               // theme is already marked for uninstall so switch to the default
  2654.               // theme
  2655.               this.cmd_useTheme(document.getElementById(PREFIX_ITEM_URI + "{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
  2656.             }
  2657.             else {
  2658.               // The theme being uninstalled is the theme to be changed to on
  2659.               // restart so clear the pending theme change.
  2660.               gPref.clearUserPref(PREF_EXTENSIONS_DSS_SWITCHPENDING);
  2661.               gPref.clearUserPref(PREF_DSS_SKIN_TO_SELECT);
  2662.               clearRestartMessage();
  2663.             }
  2664.           }
  2665.           else {
  2666.             // The theme being uninstalled is the current theme, we need to reselect
  2667.             // the default.
  2668.             this.cmd_useTheme(document.getElementById(PREFIX_ITEM_URI + "{972ce4c6-7e08-4474-a285-3208198ce6fd}"));
  2669.           }
  2670.         }
  2671.  
  2672.         // If the theme is not the current theme then it will vanish and nothing
  2673.         // will be selected so update the selection now.
  2674.         if (theme != selectedTheme) {
  2675.           if (!gExtensionsView.goDown())
  2676.             gExtensionsView.goUp();
  2677.         }
  2678.       }
  2679.       gExtensionManager.uninstallItem(getIDFromResourceURI(aSelectedItem.id));
  2680.       gExtensionsViewController.onCommandUpdate();
  2681.       if (gExtensionsView.selectedItem)
  2682.         gExtensionsView.selectedItem.focus();
  2683.       updateOptionalViews();
  2684.       updateGlobalCommands();
  2685.     },
  2686.  
  2687.     cmd_cancelUninstall: function (aSelectedItem)
  2688.     {
  2689.       gExtensionManager.cancelUninstallItem(getIDFromResourceURI(aSelectedItem.id));
  2690.       gExtensionsViewController.onCommandUpdate();
  2691.       gExtensionsView.selectedItem.focus();
  2692.       updateOptionalViews();
  2693.       updateGlobalCommands();
  2694.     },
  2695.  
  2696.     cmd_cancelInstall: function (aSelectedItem)
  2697.     {
  2698.       var name = aSelectedItem.getAttribute("name");
  2699.       var result = false;
  2700.       var opType = aSelectedItem.opType;
  2701.  
  2702.       // A search result with an action "installed" is equivalent to a pending install
  2703.       if (aSelectedItem.getAttribute("action") == "installed" && gView == "search")
  2704.         opType = OP_NEEDS_INSTALL;
  2705.  
  2706.       // Confirm cancelling the operation
  2707.       switch (opType)
  2708.       {
  2709.         case OP_NEEDS_INSTALL:
  2710.           result = confirmOperation(name, "cancelInstallTitle", "cancelInstallQueryMessage",
  2711.                                     "cancelInstallButton", "cancelCancelInstallButton",
  2712.                                     null, []);
  2713.           break;
  2714.         case OP_NEEDS_UPGRADE:
  2715.           result = confirmOperation(name, "cancelUpgradeTitle", "cancelUpgradeQueryMessage",
  2716.                                     "cancelUpgradeButton", "cancelCancelUpgradeButton",
  2717.                                     null, []);
  2718.           break;
  2719.       }
  2720.       if (!result)
  2721.         return;
  2722.  
  2723.       var id = aSelectedItem.getAttribute("addonID");
  2724.       gExtensionManager.cancelInstallItem(id);
  2725.       if (gSearchDS) {
  2726.         // Check for a search result for this entry
  2727.         var searchResult = gSearchDS.GetSource(gRDF.GetResource(PREFIX_NS_EM + "addonID"),
  2728.                                                gRDF.GetLiteral(id),
  2729.                                                true);
  2730.         if (searchResult) {
  2731.           // Remove the installed status
  2732.           gSearchDS.Unassert(searchResult,
  2733.                              gRDF.GetResource(PREFIX_NS_EM + "action"),
  2734.                              gRDF.GetLiteral("installed"),
  2735.                              true);
  2736.         }
  2737.       }
  2738.       gExtensionsViewController.onCommandUpdate();
  2739.       gExtensionsView.selectedItem.focus();
  2740.       updateOptionalViews();
  2741.       updateGlobalCommands();
  2742.     },
  2743.  
  2744.     cmd_cancelUpgrade: function (aSelectedItem)
  2745.     {
  2746.       this.cmd_cancelInstall(aSelectedItem);
  2747.     },
  2748.  
  2749.     cmd_disable: function (aSelectedItem)
  2750.     {
  2751.       if (aSelectedItem.getAttribute("plugin") == "true") {
  2752.         var name = aSelectedItem.getAttribute("name");
  2753.         var desc = aSelectedItem.getAttribute("description");
  2754.         togglePluginDisabled(name, desc);
  2755.         return;
  2756.       }
  2757.  
  2758.       var id = getIDFromResourceURI(aSelectedItem.id);
  2759.       var dependentItems = gExtensionManager.getDependentItemListForID(id, false, { });
  2760.  
  2761.       if (dependentItems.length > 0) {
  2762.         name = aSelectedItem.getAttribute("name");
  2763.         var result = confirmOperation(name, "disableTitle", "disableQueryMessage",
  2764.                                       "disableButton", "cancelButton",
  2765.                                       "disableWarningDependMessage", dependentItems);
  2766.         if (!result)
  2767.           return;
  2768.       }
  2769.       gExtensionManager.disableItem(id);
  2770.       gExtensionsViewController.onCommandUpdate();
  2771.       gExtensionsView.selectedItem.focus();
  2772.       updateOptionalViews();
  2773.       updateGlobalCommands();
  2774.     },
  2775.  
  2776.     cmd_enable: function (aSelectedItem)
  2777.     {
  2778.       if (aSelectedItem.getAttribute("plugin") == "true") {
  2779.         var name = aSelectedItem.getAttribute("name");
  2780.         var desc = aSelectedItem.getAttribute("description");
  2781.         togglePluginDisabled(name, desc);
  2782.         return;
  2783.       }
  2784.  
  2785.       gExtensionManager.enableItem(getIDFromResourceURI(aSelectedItem.id));
  2786.       gExtensionsViewController.onCommandUpdate();
  2787.       gExtensionsView.selectedItem.focus();
  2788.       updateOptionalViews();
  2789.       updateGlobalCommands();
  2790.     }
  2791.   }
  2792. };
  2793.  
  2794. //////////////////////////////////////////////////////////////////////////
  2795. // functions to support installing of themes in apps other than firefox //
  2796. //////////////////////////////////////////////////////////////////////////
  2797. function installSkin()
  2798. {
  2799.   // 1) Prompt the user for the location of the theme to install.
  2800.   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  2801.   fp.init(window, getExtensionString("installThemePickerTitle"), nsIFilePicker.modeOpen);
  2802.   try {
  2803.     fp.appendFilter(getExtensionString("themesFilter"), "*.jar");
  2804.     fp.appendFilters(nsIFilePicker.filterAll);
  2805.   } catch (e) { }
  2806.  
  2807.   var ret = fp.show();
  2808.   if (ret == nsIFilePicker.returnOK)
  2809.   {
  2810.     var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(nsIIOService);
  2811.     var fileProtocolHandler =
  2812.     ioService.getProtocolHandler("file").QueryInterface(nsIFileProtocolHandler);
  2813.     var url = fileProtocolHandler.newFileURI(fp.file).QueryInterface(nsIURL);
  2814.     InstallTrigger.installChrome(InstallTrigger.SKIN, url.spec, decodeURIComponent(url.fileBaseName));
  2815.   }
  2816. }
  2817.  
  2818. function installExtension()
  2819. {
  2820.   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  2821.   fp.init(window, getExtensionString("installExtensionPickerTitle"), nsIFilePicker.modeOpen);
  2822.   try {
  2823.     fp.appendFilter(getExtensionString("extensionFilter"), "*.xpi");
  2824.     fp.appendFilters(nsIFilePicker.filterAll);
  2825.   } catch (e) { }
  2826.  
  2827.   var ret = fp.show();
  2828.   if (ret == nsIFilePicker.returnOK)
  2829.   {
  2830.     var ioService = Components.classes['@mozilla.org/network/io-service;1'].getService(nsIIOService);
  2831.     var fileProtocolHandler =
  2832.     ioService.getProtocolHandler("file").QueryInterface(nsIFileProtocolHandler);
  2833.     var url = fileProtocolHandler.newFileURI(fp.file).QueryInterface(nsIURL);
  2834.     var xpi = {};
  2835.     xpi[decodeURIComponent(url.fileBaseName)] = url.spec;
  2836.     InstallTrigger.install(xpi);
  2837.   }
  2838. }
  2839.